2

I'm retrieving json data from json-generator.com and parsing it to create a list of companies in the below code. When i print JsonData variable i can see the data but snapshot.data is null. here's my code

import 'package:flutter/material.dart';
import './Object.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'UI_Styles/Company_Card_Style.dart';
import 'dart:convert';

class Companies extends StatefulWidget {
  @override
  _CompaniesState createState() => _CompaniesState();
}

class _CompaniesState extends State<Companies> {
  Future<List<Company>> _getCompanies() async {
    var data = await http.get("http://www.json-generator.com/api/json/get/bUYmnsimgi?indent=2");
    var jsonData = json.decode(data.body);

    List<Company> companies = [];
    for (var c in jsonData) {
      Company company = Company(
          c["name"],
          c["opportunites"],
          c["address"],
          c["city"],
          c["state"],
          c["country"],
          c["zipcode"],
          c["phone"],
          c["timezone"],
          c["pipelineRevenue"],
          c["revenueAchieved"],
          c["tags"]);
      companies.add(company);
    }
    return companies;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: FutureBuilder(
            future: _getCompanies(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                    itemCount: snapshot.data.length,
                    itemBuilder: (BuildContext context, int index) {
                      return CompanyCardStyle(company: snapshot.data[index]);
                    });
              } else {
                return Center(
                  child: CircularProgressIndicator(),
                );
              }
            }));
  }
}

Here is my company object

class Company {
  String name;
  String address;
  int opportunities;
  int pipelineRevenue;
  int revenueAchieved;
  String city;
  String state;
  String country;
  int zipcode;
  double phone;
  String timezone;
  String tags;

  Company(
      this.name,
      this.address,
      this.opportunities,
      this.pipelineRevenue,
      this.revenueAchieved,
      this.city,
      this.state,
      this.country,
      this.zipcode,
      this.phone,
      this.timezone,
      this.tags);
}

I think there is some issue with the for loop but i cant figure out what's wrong I'm new to parsing data like that.

  • You might be interested in giving a look to this thread: https://stackoverflow.com/questions/51983011/when-should-i-use-a-futurebuilder – Luis Aug 07 '20 at 04:27

3 Answers3

1

That's because the FutureBuilder returns an Error event. You can check what error it is by accessing snapshot.error (or snapshot.hasError to check if there are any error).

When I tried your code, the error said Expected a value of type 'int', but got one of type 'String'. Looks like it's problem when you are instantiating Company object. Some of properties (like opportunities) need int, but you give it in String because the value in the decoded json is String. You need to parse it to int first.

skybur
  • 346
  • 2
  • 8
1

I looked at the website and noticed that you had some of the types incorrect. For example tags is a list, but you put it as a String. The same thing with the phone number, it is supposed to be a String, not a double. And since you are not using named parameters, you will need to place your properties from the constructor in the same order whenever you create an instance of that class.

class Company {
  String name;
  String address;
  int opportunities;
  int pipelineRevenue;
  int revenueAchieved;
  String city;
  String state;
  String country;
  int zipcode;
  String phone;
  String timezone;
  List tags;

  Company(
    this.name,
    this.opportunities,
    this.address,
    this.city,
    this.state,
    this.country,
    this.zipcode,
    this.phone,
    this.timezone,
    this.pipelineRevenue,
    this.revenueAchieved,
    this.tags);
}
Unbreachable
  • 724
  • 8
  • 19
0

You were doing some things wrong:

  1. Some fields coming from the endpoint were given the wrong data type (the phone number required a String but you used a double. The tags also returns a List but you used a String.

  2. You swapped most of the constructor fields with one another when you were converting the jsonData to a Company object.

Solution:

  1. Make a factory constructor for your Company class that makes json deserialization easier. You can check the official documentation for an example.
  2. Use correct data types for each of your fields.

Note: I made the tag field a String and only access the first element in the list coming from the api.

COMPANY CLASS

class Company {
  String name;
  String address;
  int opportunities;
  int pipelineRevenue;
  int revenueAchieved;
  String city;
  String state;
  String country;
  int zipcode;
  String phone;
  String timezone;
  String tags;

  Company(
      this.name,
      this.address,
      this.opportunities,
      this.pipelineRevenue,
      this.revenueAchieved,
      this.city,
      this.state,
      this.country,
      this.zipcode,
      this.phone,
      this.timezone,
      this.tags);

  // make a constructor for converting json to a company object
  factory Company.fromJson(Map<String, dynamic> json) {
    return Company(
      json["name"],
      json["address"],
      json["opportunities"],
      json["pipelineRevenue"],
      json["revenueAchieved"],
      json["city"],
      json["state"],
      json["country"],
      json["zipcode"],
      json["phone"],
      json["timezone"],
      json["tags"][0],
    );
  }
}
  • COMPANIES WIDGET*
class Companies extends StatefulWidget {
  @override
  _CompaniesState createState() => _CompaniesState();
}

class _CompaniesState extends State<Companies> {
  Future<List<Company>> _getCompanies() async {
    var data = await http
        .get("http://www.json-generator.com/api/json/get/bUYmnsimgi?indent=2");
    var jsonData = json.decode(data.body) as List;
    List<Company> companies = [];
    // convert the json to a list of companies
    companies = jsonData
        .map((company) => Company.fromJson(company))
        .toList(); // new line
    print(companies.length);
    return companies;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          child: FutureBuilder(
              future: _getCompanies(),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  return ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, int index) {
                        // use your company card here
                        return Text(
                            'Company $index name: ${snapshot.data[index].name}');
                      });
                } else {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                }
              })),
    );
  }
}

output

void
  • 12,787
  • 3
  • 28
  • 42
  • thanks for the effort, really appreciate it. will implement the factory function. however why did you put [0] beside tags in factory function – Vishal Prabhu Aug 07 '20 at 07:08
  • Because `tag` returns a `List` so I selected the first element of the list since I didn't have an idea of what your `CompanyCardStyle` looked like. – void Aug 07 '20 at 07:09
  • ok! to display in the demo app you made. Got it, thanks – Vishal Prabhu Aug 07 '20 at 07:13