0

I am newbie of flutter

I want to load some data from my restful API by using Yii2

Provide data to API: { "account":"B0929036", "password":"12344567" } ........(more account and password)

API return data: [ { "access_token":"bugeywbhihwiuvwhe",//garbled "ip_address":"172.150.111.122", "password_hash":"gjwhubehbhfyuqbh$gy$iknb$oknwun"//garbled } ]

API post request and Model:

import 'dart:convert';
// import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;

class LoginModel {
  final String accessToken;
  final String ipAddress;
  const LoginModel({required this.accessToken, required this.ipAddress});
  factory LoginModel.fromJson(Map<String, dynamic> json) {
    return LoginModel(
      //API return
      accessToken: json['access_token'],
      ipAddress: json['ip_address'],
    );
  }
}
Future<LoginModel> createLogin(String account, String password) async {
  final response = await http.post(
    Uri.parse(
        'http://120.126.16.222/gardeners/login'), //'https://jsonplaceholder.typicode.com/users'
    headers: <String, String>{'Content-Type': 'application/json;charset=UTF-8'},
    body: jsonEncode(<String, String>{
      //input
      'account': account,
      'password': password,
    }),
  );
  if (response.statusCode == 200) {
    return LoginModel.fromJson(response.body as Map<String, dynamic>);
  } else {
    throw Exception('${response.reasonPhrase},${response.statusCode}');
  }
}

API will return like this:API return data

login_post.dart

import 'package:test_spi/models/post_test.dart';
import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);
  @override
  // ignore: library_private_types_in_public_api
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final TextEditingController _accountcontroller = TextEditingController();
  final TextEditingController _passwordcontroller = TextEditingController();
  Future<LoginModel>? _futureLogin;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Gardeners Login Data(Post) Post'),
      ),
      body: Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8),
        child: (_futureLogin == null) ? buildColumn() : buildFutureBuilder(),
      ),
    );
  }

  Column buildColumn() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        SizedBox(
          width: 300,
          height: 80,
          child: TextField(
            controller: _accountcontroller,
            decoration: const InputDecoration(
              hintText: 'Enter Account',
              labelText: "帳號",
              prefixIcon: Icon(Icons.person),
            ),
          ),
        ),
        SizedBox(
          width: 300,
          height: 80,
          child: TextField(
            controller: _passwordcontroller,
            obscureText: true,
            decoration: const InputDecoration(
              hintText: 'Enter Password',
              labelText: "密碼",
              prefixIcon: Icon(Icons.lock),
            ),
          ),
        ),
        SizedBox(
          width: 150,
          height: 48,
          child: ElevatedButton(
            onPressed: () {
              setState(() {
                _futureLogin = createLogin(
                    _accountcontroller.text, _passwordcontroller.text);
              });
            },
            child: const Text('Show'),
          ),
        ),
      ],
    );
  }

  FutureBuilder<LoginModel> buildFutureBuilder() {
    return FutureBuilder<LoginModel>(
      future: _futureLogin,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        } else if (snapshot.hasData) {
          return ListView(
            padding: const EdgeInsets.all(20),
            children: <Widget>[
              Text(
                'Access Token:${snapshot.data!.accessToken}',
              ),
              Text(
                'IP Address: ${snapshot.data!.ipAddress}',
              ),
            ],
          );
        } else if (snapshot.hasError) {
          return Text('${snapshot.error}');
        } else {
          return const Text('No data available');
        }
      },
    );
  }
}

main.dart

import 'package:flutter/material.dart';
import 'package:test_spi/homepage.dart';
import 'package:test_spi/login_post.dart';
void main()
{
  runApp(const MyApp());
}

class MyApp extends StatelessWidget
{
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context)
  {
    return MaterialApp
    (
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const LoginPage(),
    );
  }
}

Error just like this,after i enter the account and password into TextField,press the button,it should be refresh and print what i want(which are access_token and ip_address).

However,

1.when i set the response.statuscode==201

output Expection: OK,200

which means successfully connected, but didn't appear any data

2.when i set the response.statuscode==200

output Expected a value of type 'Map<String,dynamic>',but got one of type 'String'

Here are the demo page:

For 1. input For 1. input

For 1. output For 1. output

For 2. input For 2. input

For 2. output For 2. output

Any ideas what I am doing wrong? Which parts should I improve? Thanks in advance!

Chavon
  • 1

1 Answers1

0

For 1

try

if (response.statusCode == 200) {
  ...
}

to

if (response.statusCode >= 200 && response.statusCode < 300) {
  ...
}

For 2

your api response data is [{access_token: kL..., try

List<Map<String, dynamic>> body = json.decode(response.body);
return LoginModel.fromJson(body); 

hope this works for you.

  • Thanks,I appreciate you providing me with another option to consider. After I changed all of the Future to Future>, it solved my problem>. – Chavon Jul 17 '23 at 10:46