oppsig
oppsig

Reputation: 181

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

So i have a class AdsList which I want to use in future builder. I know I could have used a for loop and just stored the nested json in a list and use that in future builder, but I'm trying to use a class. in the fetchJson() method the variable parsed contains the json data and is not Null. I also commented out snapshot.length since I don't know how to return the length of the class AdsList.

I didn't paste entire file but the widget that doesn't build.

The nested json in the parsed variable has the format like this.

[
  {
    "id": 1,
    "price": 1000000
  },
  {
    "id": 2,
    "price": 2000000
  }
]

I'm a bit unsure what fetchJson() is supposed to return, or is not valid.

Future fetchJson() async {

Here is an image when the app is built. image of the list errors

It fails with this exception:

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building:
flutter: Class 'AdsList' has no instance method '[]'.
flutter: Receiver: Instance of 'AdsList'
flutter: Tried calling: [](0)

Code

import 'package:flutter/foundation.dart'
    show debugDefaultTargetPlatformOverride;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async' 
    show Future;

Future<dynamic> fetchJson() async {
  String url = "http://<hidden_nested_json>";
  final response = await http.get(url);
  var parsed = json.decode(response.body);

  AdsList ads = new AdsList.fromJson(parsed);
  print(ads);
  return ads;
}

class Ad {
  final int id;
  final int sqf;
  final int price;
  final String url;
  //final String thumbnailUrl;

  Ad({
    this.id, 
    this.sqf, 
    this.price, 
    this.url
  }) ;//, this.thumbnailUrl});

  factory Ad.fromJson(Map<String, dynamic> json) {
    return new Ad(
      finnkode: json['id'] as int,
      areal: json['sqf'] as int,
      prisantydning: json['price'] as int,
      url: json['url'] as String,
      //thumbnailUrl: json['thumbnailUrl'] as String,
    );
  }
}

class AdsList {
  final List<Ad> ads;

  AdsList({
    this.ads,
  });


  factory AdsList.fromJson(List<dynamic> parsedJson) {

    List<Ad> ads = new List<Ad>();

    ads = parsedJson.map((i)=>Ad.fromJson(i)).toList();

    return new AdsList(
      ads: ads,
    );
  }
}

class Houses extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: Container(
        child: FutureBuilder(
        future: fetchJson(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
        print(snapshot.data);
        if (snapshot.data != null) {
          return ListView.builder(
            //itemCount: snapshot.data.length,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                title: snapshot.data[index].id,
                subtitle: snapshot.data[index].price,
            );
            }
          );
        }
      },
      ),
        ) 

      );
  }
}

Upvotes: 1

Views: 1673

Answers (1)

Marcos Boaventura
Marcos Boaventura

Reputation: 4741

Your serialization is wrong! As you're passing the decoded .json which is a Map to your AdList.fromJson constructor it must receive a Map<String,dynamic> instance and not a List<dynamic>.

I add a single key adList in .json file just to be more clear.

"adList": [
  {
    "id": 1,
    "price": 1000000
  },
  {
    "id": 2,
    "price": 2000000
  }
]

In your AdList constructor you should have:

factory AdsList.fromJson(Map<String, dynamic> json) {
    // here we've a json map with a list "adList" of maps
    // which holds your ads data.
    var listOfMaps = List<Map<String,dynamic>>.from(json['adList']);

    List<Ad> ads = new List<Ad>();
    ads = listOfMaps.map(( adMap )=>Ad.fromJson( adMap )).toList();

    return new AdsList(
      ads: ads,
    );
  }

Now you don't need to change your fetch method:

Future<dynamic> fetchJson() async {
  String url = "http://<hidden_nested_json>";
  final response = await http.get(url);
  var parsed = json.decode(response.body);

  AdsList ads = new AdsList.fromJson(Map.from(parsed));
  print(ads);
  return ads;
}

Take a look at this article to clear more your serialization skills. I hope it helps.

Upvotes: 1

Related Questions