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!

2
  • Please check your API data first as i show API give you response in array Commented Jul 14, 2023 at 5:19
  • you can store data in map your current API response is List and you store api data map . Commented Jul 14, 2023 at 6:45

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks,I appreciate you providing me with another option to consider. After I changed all of the Future<LoginModel> to Future<List<dynamic>>, it solved my problem>.<
0

Add like this


  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',
          'Accept': 'application/json',
        },
        body: jsonEncode(<String, String>{
          //input
          'account': account,
          'password': password,
        }),
      );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.