Palash Dey
Palash Dey

Reputation: 84

Why I can't fetch data by Json on my Flutter App

I wasn't get any data from fake Api : https://jsonplaceholder.typicode.com/users to my flutter App. Can anyone please give me piece of advise why or how I can get those data on my app. For creating the Model file using https://app.quicktype.io/.

JsonModel File:

import 'dart:convert';

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

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

class JsonModel {
  JsonModel({
    this.id,
    this.name,
    this.username,
    this.email,
    this.address,
    this.phone,
    this.website,
    this.company,
  });

  int? id;
  String? name;
  String? username;
  String? email;
  Address? address;
  String? phone;
  String? website;
  Company? company;

  factory JsonModel.fromJson(Map<String, dynamic> json) => JsonModel(
        id: json["id"],
        name: json["name"],
        username: json["username"],
        email: json["email"],
        address: Address.fromJson(json["address"]),
        phone: json["phone"],
        website: json["website"],
        company: Company.fromJson(json["company"]),
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "username": username,
        "email": email,
        "address": address?.toJson(),
        "phone": phone,
        "website": website,
        "company": company?.toJson(),
      };
}

class Address {
  Address({
    this.street,
    this.suite,
    this.city,
    this.zipcode,
    this.geo,
  });

  String? street;
  String? suite;
  String? city;
  String? zipcode;
  Geo? geo;

  factory Address.fromJson(Map<String, dynamic> json) => Address(
        street: json["street"],
        suite: json["suite"],
        city: json["city"],
        zipcode: json["zipcode"],
        geo: Geo.fromJson(json["geo"]),
      );

  Map<String, dynamic> toJson() => {
        "street": street,
        "suite": suite,
        "city": city,
        "zipcode": zipcode,
        "geo": geo?.toJson(),
      };
}

class Geo {
  Geo({
    this.lat,
    this.lng,
  });

  String? lat;
  String? lng;

  factory Geo.fromJson(Map<String, dynamic> json) => Geo(
        lat: json["lat"],
        lng: json["lng"],
      );

  Map<String, dynamic> toJson() => {
        "lat": lat,
        "lng": lng,
      };
}

class Company {
  Company({
    this.name,
    this.catchPhrase,
    this.bs,
  });

  String? name;
  String? catchPhrase;
  String? bs;

  factory Company.fromJson(Map<String, dynamic> json) => Company(
        name: json["name"],
        catchPhrase: json["catchPhrase"],
        bs: json["bs"],
      );

  Map<String, dynamic> toJson() => {
        "name": name,
        "catchPhrase": catchPhrase,
        "bs": bs,
      };
}

Service or JsonApi File:

import 'dart:convert';

import 'package:flutter_learning_from_pageview/Model/JsonModel.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;

class JsonApi {
  bool loading = true;
  var json_Data;
  Future<JsonModel> getJsonData() async {
    var client = http.Client();
    String uri = "https://jsonplaceholder.typicode.com/users";
    var response = await client.get(Uri.parse(uri));
    var jsonModel = null;
    try {
      if (response.statusCode == 200) {
        var decode = json.decode(response.body);
        jsonModel = JsonModel.fromJson(decode);
        print(jsonModel);
      } else {
        throw Exception("falied to load");
      }
    } catch (Exception) {
      return jsonModel;
    }

    return jsonModel;
  }
}

Try to call it but As progress bar not closed it mean I didn't get the data

import 'dart:convert';


import 'package:flutter/material.dart';
import 'package:flutter_learning_from_pageview/Model/JsonModel.dart';
import 'package:flutter_learning_from_pageview/Service/JsonApi.dart';

class JsonData extends StatefulWidget {
  const JsonData({Key? key}) : super(key: key);

  @override
  _JsonDataState createState() => _JsonDataState();
}

class _JsonDataState extends State<JsonData> {
  bool loading = true;
  Future<JsonModel>? _jsonModel;
  @override
  void initState() {
    _jsonModel = JsonApi().getJsonData();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: FutureBuilder(
          future: _jsonModel,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                  //itemCount: json_Data == null ? 0 : json_Data.length,
                  itemBuilder: (context, index) {
                return ListTile(
                  title: Text(""),
                  //subtitle: Text(json_Data[index]["body"]),
                );
              });
            } else {
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
      ),
    );
  }
}

Upvotes: 0

Views: 1382

Answers (5)

  1. Make sure response.body is returning data.

  2. Avoid using ? in futures, otherwise snapshot could be empty the whole time when body is null. The ui will always show loading.

  3. To make your code look more simple:

Inside statefull widget:

late final Future<List<Data>> _futureData;

And in your initState:

@override    
void initState(){
   _futureData = provider.loadFutureData();
   super.initState();
}

Or if you don't are using provider:

@override    
void initState(){
   _futureData = loadDataFromFunction();
   super.initState();
}

Upvotes: 0

Masum Billah Sanjid
Masum Billah Sanjid

Reputation: 1189

You made some mistake so try to change it to like this. you are trying to parse list of data with just a single element.

class JsonApi {
  Future<List<JsonModel>> getJsonData() async {
    var client = http.Client();
    String uri = "https://jsonplaceholder.typicode.com/users";
    var response = await client.get(Uri.parse(uri));

    if (response.statusCode == 200) {
      return jsonModelFromJson(response.body);
    } else {
      throw Exception("falied to load");
    }
  }
}

Then try this code

late final Future<List<JsonModel>> _futureData;
  apiCalling() {
    _futureData = JsonApi().getJsonData();
  }

  @override
  void initState() {
    apiCalling();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: FutureBuilder(
          future: _futureData,
          builder: (context, AsyncSnapshot<List<JsonModel>> snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                  itemCount: snapshot.data!.length,
                  //itemCount: json_Data == null ? 0 : json_Data.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      onTap: () {
                        setState(() {});
                      },
                      title: Text(snapshot.data![index].name!),
                      //subtitle: Text(json_Data[index]["body"]),
                    );
                  });
            } else {
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
      ),
    );
  }

Upvotes: 2

Ravindra S. Patil
Ravindra S. Patil

Reputation: 14775

Try below code hope its help to you.

Your API Call:

  Future<List<dynamic>> getJobsData() async {
    String url = 'https://jsonplaceholder.typicode.com/users';
    var response = await http.get(Uri.parse(url), headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    });
    return json.decode(response.body);
  }

Your Widget:

Center(
  child: FutureBuilder<List<dynamic>>(
    future: getJobsData(),
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: ListView.builder(
            shrinkWrap: true,
            physics:const NeverScrollableScrollPhysics(),
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              var id = snapshot.data![index]['id'];
              var name = snapshot.data![index]['name'];
              var username = snapshot.data![index]['username'];
              var email = snapshot.data![index]['email'];
              var phone = snapshot.data![index]['phone'];
              return Card(
                shape: RoundedRectangleBorder(
                  side: BorderSide(
                    color: Colors.green.shade300,
                  ),
                  borderRadius: BorderRadius.circular(15.0),
                ),
                child: ListTile(
                  leading: Text(id.toString()),
                  title: Text(name),
                  subtitle: Text(
                    username + '\n' + email + '\n' + phone.toString(),
                  ),
                ),
              );
            },
          ),
        );
      }
      return const CircularProgressIndicator();
    },
  ),
),

Refer my answer here and here for get data from json API

Your Result Screen->image

Upvotes: 0

Rahul sharma
Rahul sharma

Reputation: 1574

I found your issue. You trying to fetch data in wrong jsonModel.

Remove this code

       var decode = json.decode(response.body);
       jsonModel = JsonModel.fromJson(decode);

Use this Instead

       jsonModel = jsonModelFromJson(response.body);

Your Api data is in Array format and you are trying to store in Class format.

Upvotes: 0

Hardik Mehta
Hardik Mehta

Reputation: 2425

from init state you have to change like this:

 @override
  void initState() {
     callApi();
    super.initState();
  }


    void callApi() async {
     _jsonModel = await JsonApi().getJsonData();
    }

as you are not calling that with await so, it has no data

Upvotes: 0

Related Questions