Home > Mobile >  How to fetch an array data from API and map it to the dart object?
How to fetch an array data from API and map it to the dart object?

Time:01-14

I'm trying to use Flutter documentation to map an array data (comes from API) to the dart object. The documentation uses a single Json object, not an array. I have the following codes:

Json data:

[
    {
        "channelId" :   1
        "channelTitle"  :   "Photos"
        "channelImage"  :   pr01.jpg
        "channelLastPost"   :   null
        "lastUpdate"    :   null
        "userRef"   :   1
    },
    {
        "channelId" :   2
        "channelTitle"  :   "Science"
        "channelImage"  :   pr02.jpg
        "channelLastPost"   :   "For test ...."
        "lastUpdate"    :   "2023-01-03"
        "userRef"   :   1
    }

]

ChannelListModel.dart:

class ChannelListModel {
  String creator;
  String? image;
  String title;
  String lastPost;
  String lastUpdate;

  ChannelListModel(
      {required this.creator,
      required this.image,
      required this.title,
      required this.lastPost,
      required this.lastUpdate});

  factory ChannelListModel.fromJson(Map<String, dynamic> json) {
    return ChannelListModel(
        creator: json['userRef'],
        image: json['channelImage'],
        title: json['channelTitle'],
        lastPost: json['channelLastPost'],
        lastUpdate: json['lastUpdate']);
  }
  Map<String, dynamic> toJson() {
    return {
      "userRef" : creator,
      "channelImage" : image,
      "channelTitle" : title,
      "channelLastPost" : lastPost,
      "lastUpdate" : lastUpdate
    };
  }
}

HttpRequest.dart:

class HttpServices {
  Future<List<ChannelListModel>> getChannelList() async {
    var url = base.BaseURL.channelListUrl;
    final response = await http.get(Uri.parse(url));
    if (response.statusCode == 200) {
      // If the server did return a 200 OK response,
      // then parse the JSON.
      return List<ChannelListModel>.fromJson(jsonDecode(response.body)); //I have problem in this line
    } else {
      // If the server did not return a 200 OK response,
      // then throw an exception.
      throw Exception('Failed to load album');
    }
  }
}

ChannelPage.dart:

class _ChannelsState extends State<Channels> {

  List<ChannelListModel> channels = [];

  @override
  void initState() {
    super.initState();
    channels  = getChannelsFromHttp(); // A valid array object needs to be provided here.
  }

  getChannelsFromHttp()async{
    var httpService = HttpServices();
    var result = await httpService.getChannelList();
    return result;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        itemCount: channels.length,
        itemBuilder: (context, index) =>
            ChannelCard(channelModel: channels[index]),
      ),
    );
  }
}

I want to classify my codes so I decided to provided different dart files for each part. How can I fix my code?

CodePudding user response:

Instead of

returnList<ChannelListModel>.fromJson(jsonDecode(response.body));

Try this code,

List<ChannelListModel> channels = [];
final res = jsonDecode(response.body);
channels.addAll(List<ChannelListModel>.from(
  (res).map((x) => ChannelListModel.fromJson(x))));
return channels;

Added based on comments


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

  getChannelsFromHttp()async{
    var httpService = HttpServices();
    var result = await httpService.getChannelList();
    setState((){
     channels = result;
    });
  }

CodePudding user response:

Your fromJson factory returns single ChannelListModel. You can't use List<ChannelListModel>.fromJson. Instead iterate through List and convert each json to ChannelListModel

class HttpServices {
  Future<List<ChannelListModel>> getChannelList() async {
    var url = base.BaseURL.channelListUrl;
    final response = await http.get(Uri.parse(url));
    if (response.statusCode == 200) {
      // If the server did return a 200 OK response,
      // then parse the JSON.
      //return List<ChannelListModel>.fromJson(jsonDecode(response.body));
      final data = jsonDecode(response.body) as List<dynamic>;
      return data.map((e) => ChannelListModel.fromJson(e as Map<String, dynamic>))
        .toList();

    } else {
      // If the server did not return a 200 OK response,
      // then throw an exception.
      throw Exception('Failed to load album');
    }
  }
}

CodePudding user response:

You can modify the ChannelListModel.fromJson method to handle a list of JSON objects instead of a single object. Here's one way to do it:

factory ChannelListModel.fromJson(List<dynamic> jsonList) {
    return jsonList.map((json) => ChannelListModel(
        creator: json['userRef'],
        image: json['channelImage'],
        title: json['channelTitle'],
        lastPost: json['channelLastPost'],
        lastUpdate: json['lastUpdate'])
    ).toList();
  }

You can also use jsonDecode to convert the response body to a List and then use the above method to convert the list to ChannelListModel

final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
  // If the server did return a 200 OK response,
  // then parse the JSON.
  final jsonData = jsonDecode(response.body);
  return ChannelListModel.fromJson(jsonData);
} else {
  // If the server did not return a 200 OK response,
  // then throw an exception.
  throw Exception('Failed to load album');
}

Also, you need to update the getChannelsFromHttp function to assign the result of httpService.getChannelList() to channels variable instead of calling the function again.

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

  getChannelsFromHttp() async {
    var httpService = HttpServices();
    channels = await httpService.getChannelList();
    setState(() {});
  }

This should solve the problem in your code.

  • Related