Flutter (Dart) Looping through JSON results - .length returns 0

9,600

You're really close! The problem is that return in your for loop inside the FutureBuilder builder function. The return breaks out of the loop after the first iteration, so you'll only ever get the first element of your data.

Instead, you need to generate a list of all widgets in the data and then return the list.

Two possible ways I can think to solve this (depends on your desired display widget):

=> Use a ListView.builder to handle the iteration for you:

if (snapshot.hasData) {
  List<Post> yourPosts = snapshot.data.posts;
    return ListView.builder(
      itemCount: yourPosts.length,
      itemBuilder: (BuildContext context, int index) {
        // Whatever sort of things you want to build
        // with your Post object at yourPosts[index]:
        return Text(yourPosts[index].toString());
      }
    );
  }

=> Build a List<Widget> and return a column (closest to your original approach):

if (snapshot.hasData) {
  List <Widget> myPosts;
  for(var i = 0; i < snapshot.data.posts.length; i++){
    myPosts.add(Text(snapshot.data.posts[i].name + " - " + 
      snapshot.data.posts[i].id  + " - " + i.toString())
    );
  }
  return Column( children: myPosts );
}
Share:
9,600
Jake Anderson
Author by

Jake Anderson

Updated on November 19, 2022

Comments

  • Jake Anderson
    Jake Anderson over 1 year

    I'm new to flutter and after some good progress got stuck on what i though should be a simple loop. I'm able to show a single result from the json, but unable to display them all.

    for(var i = 0; i < snapshot.data.posts.length; i++){
      return Text(snapshot.data.posts[i].name + " - " + snapshot.data.posts[i].id  + " - " + i.toString());
    }
    

    As this coded returns and outputs the first result of the dataset.

    Mr. Nice - 1 - 0
    

    The problems is that i can can't get it to output the rest of the results in the dataset. The external JSON which i'm parsing reads as follows (in full)

    [{"id":1,"name":"Mr. Nice"},{"id":2,"name":"Narco"},{"id":3,"name":"Bombasto"},{"id":4,"name":"Celeritas"},{"id":5,"name":"Magneta"},{"id":6,"name":"Super Adueduct"},{"id":7,"name":"Mr. Test"}]
    

    This full flutter page (which has been separated into it's own route) is as follows:

    import 'dart:async';
    import 'dart:convert';
    
    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;
    
    Future<PostsList> fetchPostsList() async {
      final response =
        await http.get('http://localhost:8888/heroes');
    
        if (response.statusCode == 200) {
          return PostsList.fromJson(json.decode(response.body));
        } else {
          throw Exception('Failed to load post');
        }
      }
    
      class PostsList {
        final List<Post> posts;
        PostsList({
          this.posts,
        });
    
        factory PostsList.fromJson(List<dynamic> parsedJson) {
    
        List<Post> posts = new List<Post>();
        posts = parsedJson.map((i)=>Post.fromJson(i)).toList();
    
        return new PostsList(
          posts: posts
        );
      }
    }
    
    class Post{
      final String id;
      final String name;
    
      Post({
        this.id,
        this.name
      });
    
      factory Post.fromJson(Map<String, dynamic> json){
        return new Post(
          id: json['id'].toString(),
          name: json['name'],
        );
      }
    }
    
    class HeroesPage extends StatelessWidget {
     @override
       Widget build(BuildContext context) {
         return MaterialApp(
           title: 'Fetch Data Example',
    
           home: Scaffold(
             appBar: AppBar(
               title: Text('Fetch Data Example'),
             ),
    
           body: Center(
             child: FutureBuilder<PostsList>(
               future: fetchPostsList(),
    
               builder: (context, snapshot) {
                 if (snapshot.hasData) {
    
                   for(var i = 0; i < snapshot.data.posts.length; i++){
                     return Text(snapshot.data.posts[i].name + " - " + 
                     snapshot.data.posts[i].id  + " - " + i.toString());
                   }
                   //return Text(snapshot.data.posts[1].name);
                   } else if (snapshot.hasError) {
                     return Text("${snapshot.error}");
                   }
    
                   // By default, show a loading spinner
                   return CircularProgressIndicator();
                   },
                 ),
               ),
             ),
           );
         }
    

    Now i may be going about displaying simple api data all wrong, it's just hard to find a non-firebase tutorial working with flutter and api's.

    FYI - The API running on localhost was set-up with Aqueduct by following this tutorial: https://aqueduct.io/docs/tut/getting-started/

    The code and classed where based on the Flutter docs tutorial (yet slightly modified for my json structure): https://flutter.io/cookbook/networking/fetch-data/