fluttersupabasesupabase-flutter

How to declare and save the values in a data class in Flutter


I am trying to learn Flutter and Supabase and still trying to learn its concepts coming from imperative programming. I am trying to save the returned results from the database query. Here are my current code snippets:

class Respondent {
  String id;
  String householdNumber;
  String lastname;
  String firstname;
  String? middlename;
  ...

  Respondent(
      {required this.id,
      required this.householdNumber,
      required this.lastname,
      required this.firstname,
      this.middlename,
      ...});

  static Respondent fromJson(Map<String, dynamic> json) => Respondent(
        id: json['id'],
        householdNumber: json['household_number'],
        lastname: json['lastname'],
        firstname: json['firstname'],
        middlename: json['middlename'],
        ...
      );

  Map<String, dynamic> toJson() => <String, dynamic>{
        'id': id,
        'household_number': householdNumber,
        'lastname': lastname,
        'firstname': firstname,
        'middlename': middlename,
        ...
      };
}

class HomePage extends StatefulWidget {
  final String respondentId;

  const HomePage(this.respondentId, {super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final supabase = Supabase.instance.client;
  late Respondent respondent;

  Future<void> getRespondent(String id) async {
    try {
      final response =
          await supabase.from('respondents').select().eq('id', id).single();

      setState(() {
        if (mounted) {
          print('Response' + response.toString());

          respondent = Respondent.fromJson(response);
          print('Respondent' + respondent.lastname);
          //respondent.lastname = response['last_name'].toString();
        }
      });
    } catch (error) {
      const SnackBar(
        content: Text('Unexpected Error'),
      );
    }
  }

  @override
  void initState() {
    getRespondent(widget.respondentId);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('XXX'),
      ),
      body: Text(widget.respondentId),
    );
  }
}

Coming after a successful login, I am trying to store the response results to the respondent variable. I tried printing the response and it was correct but assigning the values to the respondent variable is not working, it was null. If I tried to individually assign the values, it still does not work. A clue I guess is that if I tried to print the respondent values in a Text widget in the build method, I will get a LateInitializationError. Also I would like to have the respondent object be available to the whole application once it has values saved. How should I do it? Thanks in advance!


Solution

  • i suggest making a named constructor rather than static method that returns an object:

    From

      static Respondent fromJson(Map<String, dynamic> json) => Respondent(
            id: json['id'],
            householdNumber: json['household_number'],
            lastname: json['lastname'],
            firstname: json['firstname'],
            middlename: json['middlename'],
            ...
          );
    

    To

     Respondent.fromJson(Map<String, dynamic> json):
        id = json['id'],
        householdNumber = json['household_number'],
        lastname =  json['lastname'],
        firstname = json['firstname'],
        middlename = json['middlename'];
    

    using the initializer list.

    and one more important thing: check the correctness of the keys eg: 'lastname,...' of the map you are trying to deserialize.