2

I'm trying to create a model class with a few methods to simplify retrieving information from Firebase.

I have a "Unregistered" page where user clicks on the "Login with google" button. If my user is already registered it checks the DB to see if he completed his profile, otherwise it writes basic data to the database with a field profileCompleted: false and redirects the user to the profile page so he can complete his profile.

I'm trying to use a model here, but i'm getting all sorts of errors (just started learning flutter/dart).

I'll share some code, let me know if its not enough!

Unregistered page.

    if (user != null) {
      await prefs.setString('id', user.uid);
      // Check is already sign up
      final QuerySnapshot result = await Firestore.instance
          .collection('users')
          .where('id', isEqualTo: user.uid)
          .getDocuments();
      final List<DocumentSnapshot> documents = result.documents;

      if (documents.length == 0) {
        debugPrint("User not in DB ?");
        //debugPrint(userInfo.toString());
        // Update data to server if new user

        Firestore.instance.collection('users').document(user.uid).setData({
          'id': user.uid,
          'nickname': user.displayName,
          'photoUrl': user.photoUrl,
          'email': user.email,
          'createdAt': DateTime.now(),
          'provider': user.providerId,
          'profileCompleted': false,
          'bloodType': 'A',
          'rhType': 'Negativ',
          'donatedBefore': 'Nu',
          'lastDonation': '0'
        });
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => CompleteProfile(
                      currentUserId: user.uid,
                      userInfo: documents.single,
                    )));
      } else if (documents.single["profileCompleted"] == false) {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => CompleteProfile(
                      currentUserId: user.uid,
                      userInfo: documents.single,
                    )));
      } else {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => HomePage(
                      currentUserId: user.uid,
                      userInfo: documents.single,
                    )));
      }
    }

Complete profile page

class CompleteProfile extends StatefulWidget {
  final String currentUserId;
  final userInfo;
  static const routeName = '/profile';
  final User user;

  CompleteProfile(
      {Key key,
      this.title,
      @required this.currentUserId,
      @required this.userInfo,
      this.user})
      : super(key: key);

  final String title;

  @override
  _CompleteProfileState createState() => _CompleteProfileState(user,
      currentUserId: this.currentUserId, userInfo: this.userInfo);
}

class _CompleteProfileState extends State<CompleteProfile> {
  User user;

  _CompleteProfileState(this.user,
      {Key key, @required this.currentUserId, @required this.userInfo});
  final String currentUserId;
  final userInfo;

My issue here is that if i try to set a dropdown like this ->

child: ListTile(
title: DropdownButton<String>(
items: _bloodTypes.map((String value) {
return DropdownMenuItem<String>(
value: value, child: Text(value));
}).toList(),
style: textStyle,
value: retrieveBloodType(user.bloodType),
onChanged: (value) => updateBloodType(value),

And on default value->

  String retrieveBloodType(String value) {
    return _bloodType;
  }

I get an error that i'm getting on null.

My idea was to initialize the User model with something like User user = new User(userInfo["id"],userInfo["email"].... in which userInfo is an object retrieved from firebase. However, that throws another error that only static members can be accessed in initalizers.

My model is quite simple so here's a sneak peek (few lines, not the entire model).

class User {
  int _id;
  String _nickname;
  int get id => _id;
  String get nickname => _nickname;
  set bloodType(String newBloodType) {
    if (newBloodType.length <= 50 && newBloodType != null) {
      _bloodType = newBloodType;
    }
  }

Any idea on how id have to change this to work? The only reason i'm thinking of using models is to simplify screen widgets (so i can add all firebase logic to the model instead of the widgets).

3
  • Have a look at packages json_annotation and json_serializable. They are your best friends here. Commented Sep 28, 2019 at 12:23
  • That does seem like it would help me, however...since i dont have enough experience with dart (or similar languages) i'm having a hard time imagining how i'd implement those packages. Do you have any detailed tutorial/example that explains their use or something like that? Thanks! Commented Sep 29, 2019 at 1:12
  • @ChennaReddy had a bit of a headache, but i managed to sort it out, those packages are indeed life savers, thanks ! Commented Sep 30, 2019 at 11:08

3 Answers 3

7

This is how I would do it

import 'package:cloud_firestore/cloud_firestore.dart';

class User {
  final String userName;
  final String email;
  final String name;
  final String phoneNumber;
  final String profilePictureUrl;
  final Timestamp creationDate;

  const User(
    this.userName,
    this.email,
    this.name,
    this.phoneNumber,
    this.profilePictureUrl,
    this.creationDate
  );

  factory User.fromDocument(DocumentSnapshot document) {
    return User(
      document['userName'],
      document['email'],
      document['name'],
      document['phoneNumber'],
      document['profilePictureUrl'],
      document['creationDate']
    );
  }
Sign up to request clarification or add additional context in comments.

1 Comment

can you further explain your code the .fromDocument method? Is this where you put the retrieval/querying from firebase? I'm trying to replicate it so that for example i can already get the call the info from one place. like email = User.email; thanks!
2

it would be better if your model looks like that:

class User {
  final String userName;
  final String email;


  User({
    this.userName,
    this.email,
 
  });

 User.fromMap(Map map)
  : this(
     userName : map['userName'],
     email : map['email'],
   );

 Map<Stringm dynmic> asMap() => {
   'userName' : userName,
   'email' : email,
  }

then you can use this model to set data to firebase as follow

Firestore.instance.collection('users').document(user.uid).setData(user.asMap)

Comments

0

For creating Models, use "app.quicktype.io" Put your whole json in this link, it will itself give you the model.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.