Home > Mobile >  How to pass variable and get data from API in flutter?
How to pass variable and get data from API in flutter?

Time:12-27

enter image description here

This the first UI in there when user enter channel name and after click join then should it pass "loadData" method in there that channel name should pass to "API" and get channelname and appId from that url.

join button code

  Future<void> onJoin() async {

    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => loadData(myController.text)),
    );
  }

loadData method

import 'dart:convert';
import 'package:http/http.dart';
import '../model/appIdModel.dart';


class ApiService {
  loadData(String myController) async {
    final String url ='https://jsonplaceholder.typicode.com/posts/1=$myController';

    Future<List<Data>> getData() async {
      Response response = await get(Uri.parse(url));
      if (response.statusCode == 2000) {
        Map<String, dynamic> json = jsonDecode(response.body);
        List<dynamic> body = json['data'];

        List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
            return datas;
            } else {
            throw ('cannot fetch data');
            }
        }
  }


}

Data model code

class Data {
  String appId;
  String channelName;

  Data({
    required this.appId,
    required this.channelName,
  });

  factory Data.fromJson(Map<String, dynamic> json) {
    return Data(
        appId: json['appId'] == null ? null : json['appId'],
        channelName: json['channelName'] == null ? null : json['channelName']);
  }
}

then appId and channelName should fetch

FutureBuilder widget code show channelId and channelName (Home page code)

class _MyHomePageState extends State<MyHomePage> {
  final myController = TextEditingController();
  bool _validateError = false;

  ApiService client = ApiService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: SingleChildScrollView(
            clipBehavior: Clip.antiAliasWithSaveLayer,
            physics: BouncingScrollPhysics(),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Padding(padding: EdgeInsets.only(top: 20)),
                Padding(padding: EdgeInsets.symmetric(vertical: 20)),
                Container(
                  width: MediaQuery.of(context).size.width * 0.8,
                  child: TextFormField(
                    controller: myController,
                    decoration: InputDecoration(
                      labelText: 'Channel Name',
                      labelStyle: TextStyle(color: Colors.blue),
                      hintText: 'test',
                      hintStyle: TextStyle(color: Colors.black45),
                      errorText:
                          _validateError ? 'Channel name is mandatory' : null,
                      border: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.blue),
                        borderRadius: BorderRadius.circular(20),
                      ),
                      enabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.blue),
                        borderRadius: BorderRadius.circular(20),
                      ),
                      disabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.blue),
                        borderRadius: BorderRadius.circular(20),
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderSide: const BorderSide(color: Colors.blue),
                        borderRadius: BorderRadius.circular(20),
                      ),
                    ),
                  ),
                ),
                Padding(padding: EdgeInsets.symmetric(vertical: 30)),
                Container(
                  width: MediaQuery.of(context).size.width * 0.25,
                  child: MaterialButton(
                    onPressed: onJoin,
                    height: 40,
                    color: Colors.blueAccent,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: const <Widget>[
                        Text(
                          'Join',
                          style: TextStyle(color: Colors.white),
                        ),
                        Icon(
                          Icons.arrow_forward,
                          color: Colors.white,
                        ),
                      ],
                    ),
                  ),
                ),
                Center(
                  child: FutureBuilder(
                      future: client.getData(),
                      builder: (BuildContext context,
                          AsyncSnapshot<List<Data>> snapshot) {
                        if (snapshot.hasData) {
                          List<Data>? data = snapshot.data;
                          return ListView.builder(
                              itemBuilder: (context, index) => Column(
                                    children: [
                                      Text(
                                        data![index].channelName.toString(),
                                      ),
                                      Text(
                                        data[index].appId.toString(),
                                      ),
                                    ],
                                  ));
                        }
                        return const Center(
                          child: CircularProgressIndicator(),
                        );
                      }),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

  Future<void> onJoin() async {
    setState(() {
      myController.text.isEmpty
          ? _validateError = true
          : _validateError = false;
    });

    // await _handleCameraAndMic(Permission.camera);
    // await _handleCameraAndMic(Permission.microphone);

    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => loadData(myController.text)),
    );
  }

this is the my code to fetch data.when I run the url with channel name then data show nicely. enter image description here I tired to fetch "channelName" and "appId" using this url.

CodePudding user response:

You are doing wrong when you call onJoin, change it to this:

Future<void> onJoin() async {
  future = client.getData(myController.text);
}

then define new variable like this:

Future<List<Data>>? future;

then change ApiService to this:

class ApiService {

  final String url =
        'https://jsonplaceholder.typicode.com/posts/1';
  Future<List<Data>> getData(String myController) async {
      Response response = await get(Uri.parse(url   myController));
      if (response.statusCode == 200) { // <--- change this
        Map<String, dynamic> json = jsonDecode(response.body);
        List<dynamic> body = json['data'];

        List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
            return datas;
            } else {
            throw ('cannot fetch data');
            }
        }
}

then change your FutureBuilder to this

future != null ? FutureBuilder(//<--- add this
                  future: future,
                  builder: (context, snapshot) {
                    switch (snapshot.connectionState) {
                      case ConnectionState.waiting:
                        return const Center(
                          child: CircularProgressIndicator(),
                        );
                      default:
                        if (snapshot.hasError) {
                          return Text('Error: ${snapshot.error}');
                        } else {
                          future = null; //<--- add this
                          List<Data> data = snapshot.data ?? []; //<-- change this
                          return ListView.builder(
                              itemCount: data.length, //<-- add this
                              itemBuilder: (context, index) => Column(
                                    children: [
                                      Text(
                                        data[index].channelName.toString(),
                                      ),
                                      Text(
                                        data[index].appId.toString(),
                                      ),
                                    ],
                                  ));
                        }
                    }
                  },
                )
              : SizedBox(),//<--- add this

also as you can see in your postman result the data contain a map, not list of map, so if you expect a list you need to contact to your backend but if not you can parse it like this:

Map<String, dynamic> body = json['data'];
List<Data> datas = [Data.fromJson(body)];

also for ui issue you can't use listview inside SingleChildScrollView, for that you need set shrinkWrap to true, also set its physics to NeverScrollableScrollPhysics too:

return ListView.builder(
   shrinkWrap: true,
   physics: NeverScrollableScrollPhysics(),
   itemBuilder: ...
)
  • Related