0

So, I am pretty new to async programming in flutter, I came across a json fine which looks like this:

[{
    "Bus": ["a", "b", "c"],
    "Stops": ["1", "2", "3", "4"]
}]

So, I made a class:

class StopInfo {
    final List Bus;
    final List Stop;

    StopInfo({this.Bus, this.Stop});

    factory StopInfo.fromJson(Map<String, dynamic> json) {
        return StopInfo(
          busNames: json["Bus"],
          busStops: json["Stops"]
        );
    }
}

Now, if I am fetching Data like this:

Future<StopInfo> fetchStopData() async {

  var response = await http.get(url);

  print(response.body);

  StopInfo _stopInfo = StopInfo();

  if (response.statusCode == 200) {
  /*
  What do I do here
  */
  } else {
    throw Exception('Failed to get data');
  }
}

I am confused what to do here, Should I change something else? Thanks in advance.

6 Answers6

0

here is a simple example which shows how you can extract and use JSON data:


import "package:flutter/material.dart";
import "dart:convert";
import "package:http/http.dart" as http;

class JsonMultyParse extends StatefulWidget {
  @override
  _JsonMultyParseState createState() => _JsonMultyParseState();
}

class _JsonMultyParseState extends State<JsonMultyParse> {
  final String apiURL = 'https://jsonplaceholder.typicode.com/users';
  List<dynamic> users = [];
  void fetchJSONData() async {
    var jsonResponse = await http.get(apiURL);

    if (jsonResponse.statusCode == 200) {
      final jsonItems =
          json.decode(jsonResponse.body).cast<Map<String, dynamic>>();
      print(jsonItems[0]["address"]["street"]);
      setState(() {
        users = jsonItems;
      });

      for (dynamic user in users) {
        print(user["address"]["street"]);
      }
    } else {
      throw Exception('Failed to load data from internet');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          body: Container(
            child: Column(
              children: <Widget>[
                SizedBox(height: 20),
                RaisedButton(
                  onPressed: fetchJSONData,
                  child: Text("Fetch Data"),
                ),
                Expanded(
                  child: ListView.builder(
                      itemCount: users.length,
                      itemBuilder: (context, index) {
                        return Card(
                          child: Container(
                            height: 50,
                            padding: const EdgeInsets.all(8.0),
                            child: Text(
                              users[index]["address"]["street"],
                            ),
                          ),
                        );
                      }),
                )
              ],
            ),
          ),
        ));
  }
}

Output:

enter image description here

Ketan Ramteke
  • 10,183
  • 2
  • 21
  • 41
0

Try this,

Future<StopInfo> fetchStopData() async {

  var response = await http.get(url);

  print(response.body);

  StopInfo _stopInfo = StopInfo();

  if (response.statusCode == 200) {
  return StopInfo.fromJson(json.decode(response.body.toString())[0]);
  } else {
    throw Exception('Failed to get data');
  }
}

also modify the StopInfo

 factory StopInfo.fromJson(Map<String, dynamic> json) {
      List<String> buses=List();
      List<String> stops=List();
      json["Bus"].forEach((bus)=>buses.add(bus));
      json["Stops"].forEach((stop)=>stops.add(stop));

        return StopInfo(
          busNames: buses,
          busStops: stops
        );


    }
Nidheesh MT
  • 1,074
  • 11
  • 18
0
import 'dart:convert';

Future<List<StopInfo>> fetchStopData() async {

  var response = await http.get(url);

  print(response.body);

  StopInfo _stopInfo = StopInfo();

  if (response.statusCode == 200) {
    var body = jsonDecode(response.body);
    if(body is List) //check if it's a List, as per your example I suppose it will always be a list
      return List<StopInfo>.from(body.map(map) => StopInfo.fromJson(map));
    else if(body is Map) //check if it's a Map
      return [StopInfo.fromJson(body)];
  } else {
    throw Exception('Failed to get data');
  }
}

jsonDecode is part of dart:convert and decode a String to a dynamic value (can be a List or a Map) according to the form of the JSON data it decodes, after that you just convert it to List of StopInfo (if thats what you were expecting from the JSON

EdwynZN
  • 4,895
  • 2
  • 12
  • 15
  • A value of type 'List' can't be returned from function 'fetchStopData' because it has a return type of 'StopInfo'. – Vivek Biswas Jun 07 '20 at 06:50
  • Check again fetchStopData returns in my example List because you're asking how to extract a list from Json – EdwynZN Jun 07 '20 at 07:13
0

Add the following Function in your StopInfo class, which will convert jsonbody into List.

List<StopInfo> stopInfoResponseFromJson(String str) {
    final jsonData = json.decode(str);
    return new List<StopInfo>.from(jsonData.map((x) => StopInfo.fromJson(x)));
}

Use the above function in your fetchStopData function, like following.

String response = jsonEncode(StopInfo.body);
List<StopInfo> stopInfoResponse = stopInfoResponseFromJson(response);
Jay Dangar
  • 3,271
  • 1
  • 16
  • 35
0

Can you try the following. I generated the class using https://app.quicktype.io/

Change your StopInfo class as

// To parse this JSON data, do
//
//     final stopInfo = stopInfoFromJson(jsonString);

import 'dart:convert';

class StopInfo {
    StopInfo({
        this.bus,
        this.stops,
    });

    List<String> bus;
    List<String> stops;

    factory StopInfo.fromJson(Map<String, dynamic> json) => StopInfo(
        bus: List<String>.from(json["Bus"].map((x) => x)),
        stops: List<String>.from(json["Stops"].map((x) => x)),
    );

    Map<String, dynamic> toJson() => {
        "Bus": List<dynamic>.from(bus.map((x) => x)),
        "Stops": List<dynamic>.from(stops.map((x) => x)),
    };
}

and to convert back and forth use these functions

List<StopInfo> stopInfoFromJson(String str) => List<StopInfo>.from(json.decode(str).map((x) => StopInfo.fromJson(x)));

String stopInfoToJson(List<StopInfo> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

You probably need to use the first one and use the list to create the display widgets. The following is a minimal example

class _MyHomePageState extends State<MyHomePage> {
  String busStops = '''
    [{
    "Bus": ["a", "b", "c"],
    "Stops": ["1", "2", "3", "4"]
    }]
   ''';
  List<StopInfo> allStops = [];
  List<Widget> cardsList = [];

  @override
  void initState() {
    super.initState();
    loadPrelimData();

  }

  void loadPrelimData(){

    setState(() {
      allStops.clear();
      allStops = stopInfoFromJson(busStops);
      fillColumnChildren();
    });
  }

  void fillColumnChildren(){
    cardsList.clear();
    allStops.forEach((stopInfos) { 
      String stops = "";
      stopInfos.stops.forEach((element) { stops += element + ", "; });
      stopInfos.bus.forEach((element) {
        cardsList.add(
          //the widget that will be displayed
          Card(
          child: ListTile(title: Text("Bus:" + element),
          subtitle: Text("Stops:" + stops),
          ),
        )
        );
      });

    });

  }


  List<StopInfo> stopInfoFromJson(String str) => List<StopInfo>.from(json.decode(str).map((x) => StopInfo.fromJson(x)));
  String stopInfoToJson(List<StopInfo> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(title: Text("Bus stops"),),
      body: Center(
        child: Column(children: cardsList)
    ));
  }
}

I get the following

enter image description here

0

You model

class StopInfo {
  final List<String> busList;
  final List<String> stopList;
  StopInfo({
    this.busList,
    this.stopList,
  });

  StopInfo copyWith({
    List<String> busList,
    List<String> stopList,
  }) {
    return StopInfo(
      busList: busList ?? this.busList,
      stopList: stopList ?? this.stopList,
    );
  }

  Map<String, dynamic> toMap() {
    return {
      'busList': busList,
      'stopList': stopList,
    };
  }

  static StopInfo fromMap(Map<String, dynamic> map) {
    if (map == null) return null;

    return StopInfo(
      busList: List<String>.from(map['busList']),
      stopList: List<String>.from(map['stopList']),
    );
  }

  String toJson() => json.encode(toMap());

  static StopInfo fromJson(String source) => fromMap(json.decode(source));

  @override
  String toString() => 'StopInfo(busList: $busList, stopList: $stopList)';

  @override
  bool operator ==(Object o) {
    if (identical(this, o)) return true;

    return o is StopInfo &&
        listEquals(o.busList, busList) &&
        listEquals(o.stopList, stopList);
  }

  @override
  int get hashCode => busList.hashCode ^ stopList.hashCode;
}

Your Service

Future<StopInfo> fetchStopData() async {
  var response = await http.get(url);

  print(response.body);
  if (response.statusCode == 200) {
    return StopInfo.fromJson(response.body);
  } else {
    throw Exception('Failed to get data');
  }
}
Ulaş Kasım
  • 810
  • 1
  • 8
  • 14