hermie_brown
hermie_brown

Reputation: 329

Reading and displaying userData from Firestore - Flutter

I have my userData model as below:

class UserData {
  String id;
  String firstName;
  String lastName;
  String phoneNumber;
  String streetAddress;
  String city;
  String state;
  String postcode;
  String country;
  Timestamp createdAt;
  Timestamp updatedAt;

  UserData();

  UserData.fromMap(Map<String, dynamic> data) {
    id = data['id'];
    firstName = data['first_name'];
    lastName = data['last_name'];
    phoneNumber = data['phone_number'];
    streetAddress = data['street_address'];
    city = data['city'];
    postcode = data['postcode'];
    state = data['state'];
    country = data['country'];
    createdAt = data['created_at'];
    updatedAt = data['updated_at'];
  }

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'first_name': firstName,
      'last_name': lastName,
      'phone_number': phoneNumber,
      'street_address': streetAddress,
      'city': city,
      'postcode': postcode,
      'state': state,
      'country': country,
      'created_at': createdAt,
      'updated_at': updatedAt,
    };
  }
}

I have my Notifier class which I use to read and write userData to Firestore. Since this is userData, there will only be an instance per logged in user as they can only have one document holding their profile information.

class UserDataNotifier with ChangeNotifier {
  UserData _currentLoggedInUserData;

  Query userDataCollection = Firestore.instance.collection('userData');

  UserData get currentLoggedInUserData => _currentLoggedInUserData;

  set currentLoggedInUserData(UserData userData) {
    _currentLoggedInUserData = userData;
    notifyListeners();
  }

  getUserData(UserDataNotifier userDataNotifier) async {
    String userId = (await FirebaseAuth.instance.currentUser()).uid;

    await Firestore.instance.collection('userData').document(userId).get().then(
            (value) => _currentLoggedInUserData = UserData.fromMap(value.data));

    notifyListeners();
  }

  Future createOrUpdateUserData(UserData userData, bool isUpdating) async {
    String userId = (await FirebaseAuth.instance.currentUser()).uid;

    CollectionReference userDataRef = Firestore.instance.collection('userData');

    if (isUpdating) {
      userData.updatedAt = Timestamp.now();

      await userDataRef.document(userId).updateData(userData.toMap());
      print('updated userdata with id: ${userData.id}');
    } else {
      userData.createdAt = Timestamp.now();

      DocumentReference documentReference = userDataRef.document(userId);

      userData.id = documentReference.documentID;

      await documentReference.setData(userData.toMap(), merge: true);
      print('created userdata successfully with id: ${userData.id}');
    }
    notifyListeners();
  }
}

How do I go about reading and displaying my userData in my profile screen?

Here's my Profile form screen:

class ProfileFormScreen extends StatefulWidget {
  static const String id = 'profile_form';

  @override
  _ProfileFormScreenState createState() => _ProfileFormScreenState();
}

class _ProfileFormScreenState extends State<ProfileFormScreen> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  UserData _currentLoggedInUserData;

  //global declarations
  String selectedBusinessTypeDropDownValue = 'Fashion';
  String selectedCountryDropDownValue = 'India';
  String email;

  bool showSpinner = false;

  _saveUserData(BuildContext context) {
    UserDataNotifier userNotifier =
        Provider.of<UserDataNotifier>(context, listen: false);

    if (!_formKey.currentState.validate()) {
      return;
    }
    _formKey.currentState.save();
    userNotifier.createOrUpdateUserData(_currentLoggedInUserData, false);
    Navigator.pop(context);
  }

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

    UserDataNotifier userDataNotifier =
        Provider.of<UserDataNotifier>(context, listen: false);

    if (userDataNotifier.currentLoggedInUserData != null) {
      _currentLoggedInUserData = userDataNotifier.currentLoggedInUserData;
      print(_currentLoggedInUserData.id);
    } else {
      _currentLoggedInUserData = UserData();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Edit Profile'),
      ),
      body: ModalProgressHUD(
        inAsyncCall: showSpinner,
        child: SingleChildScrollView(
          padding: EdgeInsets.only(top: 20.0),
          child: Form(
            autovalidate: true,
            key: _formKey,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                LabelTextPadding(text: 'Business Information'),

                //location
                RegularTextPadding(regText: 'Location'),
                //address 1
                _buildAddress(),
                //city
                _buildCityField(),
                //postcode
                _buildPostcode(),
                //state
                _buildStateField(),
                //country
                _buildCountry(),

                SizedBox(
                  height: 20.0,
                ),
                DividerClass(),
                SizedBox(
                  height: 20.0,
                ),

                //Personal information
                LabelTextPadding(
                  text: 'Personal Information',
                ),
                _buildFirstNameField(),
                _buildLastNameField(),
                _buildPhoneNumberField(),
                _buildButtons(),
              ],
            ),
          ),
        ),
      ),
    );
  }

  //business information
  _buildAddress() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.streetAddress,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.streetAddress = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration:
            kTextFieldDecoration.copyWith(hintText: 'house and street address'),
      ),
    );
  }

  _buildCityField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.city,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.city = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'enter city'),
      ),
    );
  }

  _buildPostcode() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.postcode,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.postcode = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'enter postcode'),
      ),
    );
  }

  _buildStateField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.state,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.state = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'enter state'),
      ),
    );
  }

  _buildCountry() {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.all(Radius.circular(0.5)),
        border: Border.all(
          color: kThemeStyleButtonFillColour,
          width: 1,
        ),
      ),
      padding: const EdgeInsets.fromLTRB(10.0, 10.0, 20.0, 0.0),
      margin: EdgeInsets.all(20.0),
      child: Center(
        child: DropdownButton(
          value: _currentLoggedInUserData.country == null
              ? selectedCountryDropDownValue
              : _currentLoggedInUserData.country,
          icon: Icon(
            FontAwesomeIcons.caretDown,
            color: kThemeStyleButtonFillColour,
          ),
          elevation: 15,
          underline: Container(
            height: 0,
            color: kThemeStyleButtonFillColour,
          ),
          items: country
              .map(
                (country) =>
                    DropdownMenuItem(value: country, child: Text(country)),
              )
              .toList(),
          onChanged: (newValue) {
            setState(() {
              selectedCountryDropDownValue = newValue;
              _currentLoggedInUserData.country = newValue;
            });
          },
        ),
      ),
    );
  }

  //user personal info build
  _buildFirstNameField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.firstName,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.firstName = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'your first Name'),
      ),
    );
  }

  _buildLastNameField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.lastName,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.lastName = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'your last name'),
      ),
    );
  }

  _buildPhoneNumberField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.phoneNumber,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.phoneNumber = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration:
            kTextFieldDecoration.copyWith(hintText: 'your phone number'),
      ),
    );
  }

  _buildButtons() {
    return Padding(
      padding: const EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Buttons(
              onPressedButton: () {
                Navigator.pop(context);
              },
              buttonLabel: 'Cancel',
              buttonColour: kThemeStyleButtonFillColour,
              buttonTextStyle: kThemeStyleButton),
          SizedBox(
            width: 15.0,
          ),
          Buttons(
              onPressedButton: () => _saveUserData(context),
              buttonLabel: 'Save',
              buttonColour: kThemeStyleButtonFillColour,
              buttonTextStyle: kThemeStyleButton),
        ],
      ),
    );
  }
}

class TextInputFieldValidator {
  static String validate(String value) {
    if (value.isEmpty) {
      return 'This field can\'t be empty, you must enter a text';
    }
    if (value.length < 3) {
      return 'You must enter at least a word';
    }
  }
}

Here's what I've tried:

  getUserData(UserDataNotifier userDataNotifier) async {
    String userId = (await FirebaseAuth.instance.currentUser()).uid;

    await Firestore.instance.collection('userData').document(userId).get();
    notifyListeners();
  }

Upvotes: 1

Views: 517

Answers (1)

Scott
Scott

Reputation: 236

I think you would start by assigning a variable, like this:

var myVar =  await Firestore.instance.collection('userData').document(userId).get();
var yourVariable = myVar.data()["YourFieldNameInFireStore"];

You might want to look into Provider or otherwise using ChangeNotifier.

An example for that from pieces of code, not tailored to your question and typed up here so possibly containing typos / missing information:

class Muser extends ChangeNotifier {
  FirebaseUser firebaseUser;
  // this example uses FirebaseAuth, not anything from FireStore,
  // but you could easily add variables to your User class here such as
  // userAge for example, which you could update in your getUserData method or something
  fauth.User fAuthUser = fauth.FirebaseAuth.instance.currentUser;

  Muser({
    this.firebaseUser, this.userAge,
  });

  getUserData() {
  }
  int userAge;
  Map<dynamic, int> _specialCalculatedUserInfo;

  Map<dynamic, int> get specialCalculatedUserInfo{
    if (_specialCalculatedUserInfo== null) {
      _specialCalculatedUserInfo= _calculateUserInfo();
    }
    notifyListeners();
    return _specialCalculatedUserInfo;
  }

}


class ProfileViewState extends State<ProfileView> {

  @override
  void dispose() {
    // TODO: implement dispose for controllers
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: <Widget>[
          Column(
            children: <Widget>[
              Text("Your Profile"),
              Consumer<Muser>(
                builder: (context, user, child) {
                  return
                      Column(
                    children: [
                      Text("Age: ${user.userAge}"),
                      CircleAvatar(
                        radius: 50,
                        backgroundColor: Colors.brown.shade600,
                        backgroundImage: user.firebaseUser.photoUri.isEmpty
                            ? AssetImage("assets/images/icon.png")
                            : NetworkImage(user.getPhotoURL()),
                       ),
                     ],
                  );
                }
             )
           ]
         )
      );
    }
}

Upvotes: 1

Related Questions