How to show a progress Dialog before data loading in flutter?

S. M. Asif picture S. M. Asif · Jul 23, 2019 · Viewed 19.4k times · Source

In my Flutter project, I am doing API calls to fetch data by GET request. After parsing the JSON object from the response, I just show the value in the Text widget. While the data takes time to load, in the meantime my Text widgets show null.

For the API calling section I have the following code-

class Webservice {
  Future<T> load<T>(Resource<T> resource) async {
    var jwt = await LocalStore().getJWT();
    print(jwt);

    final response = await http.get(resource.url,
        headers: {
          'Content-Type': 'application/json',
          'token': '${Constants.TOKEN}',
          'jwt': '$jwt',
        }
    );
    if(response.statusCode == 200) {
      print('${response.body}');
      return resource.parse(response);
    } else {
      throw Exception('Failed to load data!');
    }
  }
}

I made a Model class for JSON parsing-

class Category {
  int catNote;
  int catTodo;
  int catRem;
  int catTag;
  int catUrgent;
  int catWork;
  int catOffice;
  int catPersonal;
  
  Category(
      {this.catNote,
        this.catTodo,
        this.catRem,
        this.catTag,
        this.catUrgent,
        this.catWork,
        this.catOffice,
        this.catPersonal});

  Category.fromJson(Map<String, dynamic> json) {
    catNote = json['cat_note'];
    catTodo = json['cat_todo'];
    catRem = json['cat_rem'];
    catTag = json['cat_tag'];
    catUrgent = json['cat_urgent'];
    catWork = json['cat_work'];
    catOffice = json['cat_office'];
    catPersonal = json['cat_personal'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['cat_note'] = this.catNote;
    data['cat_todo'] = this.catTodo;
    data['cat_rem'] = this.catRem;
    data['cat_tag'] = this.catTag;
    data['cat_urgent'] = this.catUrgent;
    data['cat_work'] = this.catWork;
    data['cat_office'] = this.catOffice;
    data['cat_personal'] = this.catPersonal;
    return data;
  }

  static Resource<Category> get allCategory {
    return Resource(
        url: '${Constants.BASE_URL}category',
        parse: (response) {
          print('my result ${response.body}');
          final result = json.decode(response.body);

          Category category = Category.fromJson(result) ;
          return category;

        }
    );

  }

}

Now, in my main class, I have created one function like below-

  void _getAllCategories() {
    Webservice().load(Category.allCategory).then((newsArticles) => {
        setState(() => {
      _category = newsArticles
    })
  });
 }

After that, I have called the function inside the initState function and saved the value in the _category object.

Then inside the Widget build(BuildContext context) function for Text widget I have used the value from _category object like below using a ternary operator to check whether the object is null or not. If it's null then it should show 0 and if it is not null then should show the original value-

child: _category ==null?
                Text('0',
                style: TextStyle(
                    fontSize: 30,
                    fontWeight: FontWeight.bold
                ),
                ):
                Text('${_category.catToDo}',
                  style: TextStyle(
                      fontSize: 30,
                      fontWeight: FontWeight.bold
                  ),
                )

But it is still showing null whiling taking few second for data loading and shows output like below-

enter image description here

So, I need a solution to show a progress dialog or just show the default value as 0 while the data takes time to load. It would be very nice if someone helps me out with this code.

Answer

Muldec picture Muldec · Jul 23, 2019

Use a FutureBuilder to control the rendering during the load time;

  final categories = Webservice().load(Category.allCategory);

  Widget build(BuildContext context) {
    return FutureBuilder(
      future: categories,
      builder: (ctx, snapshot) {
        var value = (snapshot.connectionState == ConnectionState.done) ? '${_category.catToDo}' : '0';

        return Text(
          value,
          style: TextStyle(
            fontSize: 30,
            fontWeight: FontWeight.bold
          ),
        );
      }
    );
  }

Or if you want to display a loading animation :

  final categories = Webservice().load(Category.allCategory);

  Widget build(BuildContext context) {
    return FutureBuilder(
      future: categories,
      builder: (ctx, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return Text(
            '${_category.catToDo}',
            style: TextStyle(
              fontSize: 30,
              fontWeight: FontWeight.bold
            ),
          );
        }
        else {
          return CircularProgressIndicator();
        }
      }
    );
  }