0

I have a problem to load a list from a class that the class need data from several database

The database:

A. userdata (_id, name, phone)

B. mariage status (_id, userID, mariageStatus)

--> "_id" in userdata & "userID" in marriage status are thing to be matched

read the userdata:

class User {
  final String idUser,
      name,
      phone;

  User(
      {this.idUser,
      this.name,
      this.phone});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
        idUser: json['_id'],
        name: json['name'],
        phone: json['phone']);
  }
}

List<User> userFromJson(jsonData) {
  List<User> result =
      List<User>.from(jsonData.map((item) => User.fromJson(item)));

  return result;
}

// index
Future<List<User>> fetchUser() async {
  String route = AppConfig.API_ENDPOINT + "userdata";
  final response = await http.get(route);
  if (response.statusCode == 200) {
    var jsonResp = json.decode(response.body);
    
    return userFromJson(jsonResp);
  } else {
    throw Exception('Failed load $route, status : ${response.statusCode}');
  }
}

while to read the marriage:

class Marriage{
  final String idUser, mariageStatus;

  Marriage(
      {this.idUser,
      this.mariageStatus});

  factory Marriage.fromJson(Map<String, dynamic> json) {
    return Marriage(
        idUser: json['userID'],
        name: json['mariageStatus']);
  }
}

List<Marriage> marriageFromJson(jsonData) {
  List<Marriage> result =
      List<Marriage>.from(jsonData.map((item) => Marriage.fromJson(item)));

  return result;
}

// index
Future<List<Marriage>> fetchMarriage() async {
  String route = AppConfig.API_ENDPOINT + "marriage";
  final response = await http.get(route);
  if (response.statusCode == 200) {
    var jsonResp = json.decode(response.body);
    
    return marriageFromJson(jsonResp);
  } else {
    throw Exception('Failed load $route, status : ${response.statusCode}');
  }
}

then how to make a list off combination class like this?

class User_Mariage {
  final String idUser,
      name,
      phone,
      mariageStatus;

  User(
      {this.idUser,
      this.name,
      this.phone,
      this.mariageStatus});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
        idUser: 
        name: 
        phone: 
        mariageStatus: 
  }
}

List<User> userFromJson(jsonData) {
  List<User> result =
      List<User>.from(jsonData.map((item) => User.fromJson(item)));

  return result;
}

of if there are another better way to make the list, please let me know, thank you very much

Alfan
  • 19
  • 5

1 Answers1

0

For me it looks like you are using the wrong database query. Maybe there is a possibility to use foreign keys (userId).

There are different approaches to combine the data.

Here is one example, where you could combine classes by reference and use getter

Your original User class:

import 'dart:convert';

class User {
  final String id, name, phone;

  User({
    required this.id,
    required this.name,
    required this.phone,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(id: json['_id'], name: json['name'], phone: json['phone']);
  }
}

List<User> userFromJson(dynamic jsonData) {
  return List<User>.from(jsonData.map((item) => User.fromJson(item)));
}

Future<List<User>> fetchUser() async {
  String route = AppConfig.API_ENDPOINT + "userdata";
  final response = await http.get(route);
  if (response.statusCode == 200) {
    var jsonResp = json.decode(response.body);
    return userFromJson(jsonResp);
  } else {
    throw Exception('Failed load $route, status : ${response.statusCode}');
  }
}

Your original Mariage class

import 'dart:convert';

class Marriage {
  final String idUser, mariageStatus;

  Marriage({required this.idUser, required this.mariageStatus});

  factory Marriage.fromJson(Map<String, dynamic> json) {
    return Marriage(
        idUser: json['userID'], mariageStatus: json['mariageStatus']);
  }
}

List<Marriage> marriageFromJson(dynamic jsonData) {
  return List<Marriage>.from(jsonData.map((item) => Marriage.fromJson(item)));
}

// index
Future<List<Marriage>> fetchMarriage() async {
  String route = AppConfig.API_ENDPOINT + "marriage";
  final response = await http.get(route);
  if (response.statusCode == 200) {
  var jsonResp = json.decode(response.body);
    //'[{"_id":"6194a2e65c504crb1d9af81d","userID":"6782452bd2ab63488c9f2663","mariageStatus":"Single"},{"_id":"6194a2959c534c01ft9rf24c","userID":"6785p58b41894b50b22db401","mariageStatus":"Married"}]'
  return marriageFromJson(jsonResp);
  } else {
    throw Exception('Failed load $route, status : ${response.statusCode}');
  }
}

A UserWithMariageStatus class, which will take User and Mariage Reference:

import 'package:flutter_fetch_data/mariage.dart';
import 'package:flutter_fetch_data/user.dart';

class UserWithMariageStatus {
  final User user;
  final Marriage mariage;

  UserWithMariageStatus(this.user, this.mariage);

  String get userId => user.id;
  String get name => user.name;
  String get phone => user.phone;
  String get mariageStatus => mariage.mariageStatus;
}

List<UserWithMariageStatus> combineUserWithMarriageStatus(
    List<User> user, List<Marriage> userMariage) {
  List<UserWithMariageStatus> result = [];
  // if userId is unique, iterate the lists and combine
  for (var item in userMariage) {
    result.add(UserWithMariageStatus(
        user.singleWhere((element) => element.id == item.idUser), item));
  }
  return result;
}

Use it in your fetch calling function:

import 'package:flutter_fetch_data/mariage.dart';
import 'package:flutter_fetch_data/user.dart';
import 'package:flutter_fetch_data/user_with_mariage.dart';

void main(List<String> args) async {
  List<User> userList = await fetchUser();

  for (var user in userList) {
    print("id: ${user.id}, name: ${user.name}, phone: ${user.phone}");
  }

  List<Marriage> mariageList = await fetchMarriage();
  for (var mariage in mariageList) {
    print("id: ${mariage.idUser}, mariageStatus: ${mariage.mariageStatus}");
  }

  List<UserWithMariageStatus> userWithMariageList =
      combineUserWithMarriageStatus(userList, mariageList);
  for (var userWithMariage in userWithMariageList) {
    print(
        "id: ${userWithMariage.userId}, name: ${userWithMariage.name}, phone: ${userWithMariage.phone}, mariageStatus: ${userWithMariage.mariageStatus}");
  }
}

In a FutureBuilder, you could use it like that:

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<List<UserWithMariageStatus>>? getUserWithMarriageList() async {
    final user = await fetchUser();
    final marriage = await fetchMarriage();
    return combineUserWithMarriageStatus(user, marriage);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Test Fetch Future",
      home: Scaffold(
        body: FutureBuilder<List<UserWithMariageStatus>>(
          future: getUserWithMarriageList(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView(
                  children: snapshot.data!
                      .map((e) => ListTile(
                          title: Text(
                              "id: ${e.userId}, name: ${e.name}, phone: ${e.phone}, marriage: ${e.mariageStatus}")))
                      .toList());
            }
            return const CircularProgressIndicator();
          },
        ),
      ),
    );
  }
}
Anneress
  • 171
  • 8
  • thank you very much, but for the http request section is supposed to be what? – Alfan Nov 18 '21 at 08:22
  • For the first and third approach, it would be the same fetch request as before. – Anneress Nov 18 '21 at 08:25
  • is the "before" here refer to my fetch function for each class? – Alfan Nov 18 '21 at 08:41
  • Yes it is. For the second approach I added two examples how you could fetch the data and create the list of objects. – Anneress Nov 18 '21 at 09:07
  • based on the first approach, the "item" here is refer to what things?, and how that paramenter works?, because it turn out to undefined name "item" in my IDE – Alfan Nov 22 '21 at 06:39
  • or would you write down full script of the first approach (include both classes factory, list, and future list)? – Alfan Nov 22 '21 at 07:02
  • Sorry I missed a var declaration in the for loop before item. – Anneress Nov 22 '21 at 10:19
  • Ok I added a working example to the first approach. Cause I doesn't have a backend, I used some example data in the main function instead of fetching the data. – Anneress Nov 22 '21 at 10:38
  • i'm bad on the syntax when replacing static value to value on variable / value on database, would you help me to use at least value on variable for the example? – Alfan Nov 22 '21 at 13:08
  • also would you type the comment for the line that contain operation? – Alfan Nov 22 '21 at 13:11
  • and also for the second approach, what is "" means?, by what it should be replaced? – Alfan Nov 22 '21 at 16:04
  • In valid json data you always have a key-value pair. So the jsonData need a key for the list of values. Something like: { "values" : [ { "_id" : "0", "name" : "test", "phone" : "123"} , ] } – Anneress Nov 23 '21 at 10:34
  • Can you provide example raw value from fetchUser and fetchMariage? – Anneress Nov 23 '21 at 10:38
  • -> from userdata: [{"_id":"6782452bd2ab63488c9f2663","name":"Iksans","phone":"085432232726"},{"_id":"6785p58b41894b50b22db401","name":"Anto","phone":"089142448524"}] -> from marriage: [{"_id":"6194a2e65c504crb1d9af81d","userID":"6782452bd2ab63488c9f2663","mariageStatus":"Single"},{"_id":"6194a2959c534c01ft9rf24c","userID":"6785p58b41894b50b22db401","mariageStatus":"Married"}] – Alfan Nov 24 '21 at 08:39
  • I know if it for attribute in database like "return UserWithMarriageStatus(user["_id"], user["name"], user["phone"], marriage["mariageStatus"]);" but what is the key means in "List> userList = List>.from(user[""]);"? – Alfan Nov 24 '21 at 08:44
  • Cause your raw values doesn't look like I expected you can ignore [""] and use the jsonData.map((item) => User.fromJson(item)) from your code instead. I will edit and provide a simplified answer tomorrow. – Anneress Nov 24 '21 at 14:50
  • okay, thank you very much – Alfan Nov 25 '21 at 01:17
  • is it possible if void main(List args) async written in Future async ? – Alfan Nov 29 '21 at 07:29
  • If the answer helped you, it would be nice to upvote. Sorry, I can't understand your question. – Anneress Dec 01 '21 at 06:22
  • I like to upvote, but I'm sorry honestly my reputation is not sufficient yet to upvote, because this account is new, but your answer was so helpful – Alfan Dec 02 '21 at 20:43
  • in my script, the class is called by FutureBuilder widget, so how the UserWithMariageStatus class can be start called with Future for example like User class and Marriage class? – Alfan Dec 02 '21 at 20:48
  • Ok I added an example with a FutureBuilder. You could mark it as answer, cause you opened the question. ;) – Anneress Dec 06 '21 at 14:21
  • oke I mark it, also still waiting the future builder example – Alfan Dec 07 '21 at 23:05
  • @Alfan Thank you! I added the future builder example already. Please take a look at the end of the answer. – Anneress Dec 13 '21 at 07:07