简体   繁体   中英

How do I resolve a JSON object received from localhost in FutureBuilder

I have the following JSON hosted on localhost and am trying to resolve it in a FutureBuilder widget. I cannot resolve the data from the Json to display using the FutureBuilder widget. All I get is "Instance of LiteratureDataModel". Moreover, I cannot get the length of the data snapshot. The error I get is "The getter length isn't defined for the type Object"

{
    "data": [
        {
            "authors": "author_name1",
            "edition": "publication_edition1",
            "id": 1,
            "pubdate": "publication_date1",
            "publisher": "publisher1",
            "source": "literature_source1",
            "title": "literature_title1"
        },
    {
            "authors": "author_name2",
            "edition": "publication_edition2",
            "id": 2,
            "pubdate": "publication_date2",
            "publisher": "publisher2",
            "source": "literature_source2",
            "title": "literature_title2"
        }
    ]
}

I generated the model class for the above Json using the following link:

https://app.quicktype.io/

Here is the class that was generated. I modified it to use null safety. The list of map objects according to the JSON prints successfully in the LiteratureDataModel factory constructor. So, the data is successfully received

class LiteratureDataModel {
  LiteratureDataModel({
    this.ultLiteratureDataModel,
  });

  final List<LiteratureModel>? ultLiteratureDataModel;

  factory LiteratureDataModel.fromJson(Map<String, dynamic> json) => LiteratureDataModel(
    ultLiteratureDataModel: List<LiteratureModel>.from(json["data"].map((data) {
      print(data);
      return LiteratureModel.fromJson(data);
    })).toList(),
  );

  Map<String, dynamic> toJson() => {
    "data": List<dynamic>.from(ultLiteratureDataModel!.map((data) => data.toJson())),
  };
}

class LiteratureModel {
  LiteratureModel({
    this.authors,
    this.edition,
    this.id,
    this.pubdate,
    this.publisher,
    this.source,
    this.title,
  });

  final String? authors;
  final String? edition;
  final int? id;
  final String? pubdate;
  final String? publisher;
  final String? source;
  final String? title;

  factory LiteratureModel.fromJson(Map<String, dynamic> json) => LiteratureModel(
    authors: json["authors"],
    edition: json["edition"],
    id: json["id"],
    pubdate: json["pubdate"],
    publisher: json["publisher"],
    source: json["source"],
    title: json["title"],
  );

  Map<String, dynamic> toJson() => {
    "authors": authors,
    "edition": edition,
    "id": id,
    "pubdate": pubdate,
    "publisher": publisher,
    "source": source,
    "title": title,
  };
}

Here is the widget for displaying the data:

class Literature extends StatelessWidget {

  final LiteratureService _literatureService = LiteratureService();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(24.0),
      child: Container(
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.all(Radius.circular(12)),
        ),
        child: Center(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: FutureBuilder(
                future: _literatureService.fetchLiterature(http.Client()),
                builder: (context, snapshot){
                  if (snapshot.hasData)
                    //return Text("${snapshot.data!}");
                    return ListView.builder(
                      //itemCount: snapshot.data!.length,
                        itemBuilder: (context, index){
                      return Text("${snapshot.data!}");
                    });
                  else
                    return CircularProgressIndicator();
                },
              ),
            )
        ),
      ),
    );
  }
}

The json is hosted on localhost, from which I can successfully pull the json. Here is the class used for fetching the json from local host

class LiteratureService {
  LiteratureDataModel literatureFromJson(String literature) {
    //print(literature);
    return LiteratureDataModel.fromJson(json.decode(literature));
  }

  String literatureToJson(LiteratureDataModel literatureDataModel) => json.encode(literatureDataModel.toJson());

  Future fetchLiterature(http.Client client) async {
    final response = await client.get(Uri.parse("http://localhost_ip_address:8000/literature/ultliterature.json"));
    //print("Http response: ${response.body}");
    return literatureFromJson(response.body);
  }
}

I referred to the following link to solve the problem, but could not solve it:

*SOLVED* Use json data stored in class in future builder

In the above link, the OP faced a similar issue as I did. I followed the changes recommended in the correct answer but realized its just another way of creating factory constructor that is there in LiteratureDataModel class. Moreover, I still could not get the length of the data snapshot.

I referred to the below link as well, which shows different ways of JSON serialization and deserialization as well, and still could not solve the problem.

https://bezkoder.com/dart-flutter-parse-json-string-array-to-object-list/#DartFlutter_parse_JSON_string_into_Nested_Object

What am I doing wrong in my code? Any advice on needed corrections to my code will be helpful.

I solved the problem by omitting the LiteratureDataModel class and changing the fetchLiterature() function in the following way:

Future<List<LiteratureModel>> fetchLiterature(http.Client client) async {
    final response =
        await client.get(Uri.parse("http://localhost_ip_address:8000/literature/literature.json"));
    List<LiteratureModel> literatureModel = List<LiteratureModel>.from(
        json.decode(response.body)["data"].map((data) => LiteratureModel.fromJson(data)).toList());
    return literatureModel;
  }

I also made the following changes to FutureBuilder using this link as a guide

builder: (context, AsyncSnapshot<List<LiteratureModel>> snapshot)

If anyone knows a better way of solving the question I posted, please let me know

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM