Caio Alfonso
Caio Alfonso

Reputation: 130

Flutter not showing BLoC stream value on TextField widget

I am trying to make a screen where the user can add a person's birthday in one moment, but in another moment the same screen should load the data from Firebase and display in the TextFields the value loaded. I am using BLoC with stream to perform this. I can load the data from Firebase correctly and pass it to the screen with StreamBuilders in each TextField, but the values are not showing, even though the streams contains the correct value. In the same page I use some DropdownButtons for selectable data and they receive and show the value just fine. I'm not sure what am I doing wrong.

This is the code for each TextField:

class InputField extends StatelessWidget {

  final IconData icon;
  final String hint;
  final bool obscure;
  final TextInputType type;
  final Stream<String> stream;
  final Function(String) onChanged;

  InputField({this.icon, this.hint, this.obscure, this.type, this.stream, this.onChanged});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<String>(
      stream: stream,
      builder: (context, snapshot) {
        return TextField(
          onChanged: onChanged,
          keyboardType: type != null ? type : null,
          decoration: InputDecoration(
            icon: icon == null ? null : Icon(icon, color: Colors.white,),
            hintText: hint,
            hintStyle: TextStyle(color: Colors.white),
            focusedBorder: UnderlineInputBorder(
              borderSide: BorderSide(color: Theme.of(context).primaryColor)
            ),
            contentPadding: EdgeInsets.only(
              left: 5,
              right: 30,
              bottom: 30,
              top: 30
            ),
            errorText: snapshot.hasError ? snapshot.error : null
          ),
          style: TextStyle(color: Colors.white),
          obscureText: obscure,
        );
      }
    );
  }
}

This is where I initialize the input types:

                  return Padding(
                    padding: EdgeInsets.all(16.0),
                    child: SingleChildScrollView(
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          InputField(
                            icon: Icons.person_outline,
                            hint: "Nome do aniversariante",
                            obscure: false,
                            type: TextInputType.text,
                            stream: _birthdayBloc.outName,
                            onChanged: _birthdayBloc.changeName,
                          ),
                          InputField(
                            icon: Icons.phone,
                            hint: "Telefone",
                            obscure: false,
                            type: TextInputType.text,
                            stream: _birthdayBloc.outPhone,
                            onChanged: _birthdayBloc.changePhone,
                          ),
                          InputField(
                            icon: Icons.email,
                            hint: "E-mail",
                            obscure: false,
                            type: TextInputType.text,
                            stream: _birthdayBloc.outEmail,
                            onChanged: _birthdayBloc.changeEmail,
                          ),
                          DropdownWidget(
                            isCenter: false,
                            icon: Icons.list,
                            arrowIcon: Icons.keyboard_arrow_down,
                            hint: "Selecione uma categoria",
                            items: _birthdayBloc.getCategoryList(),
                            stream: _birthdayBloc.outCategory,
                            onChanged: _birthdayBloc.changeCategory,
                          ),
                          DropdownWidget(
                            isCenter: false,
                            icon: Icons.notifications,
                            arrowIcon: Icons.keyboard_arrow_down,
                            hint: "Selecione a notificação",
                            items: _birthdayBloc.getNotificationList(),
                            stream: _birthdayBloc.outNotification,
                            onChanged: _birthdayBloc.changeNotification,
                          ),
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: <Widget>[
                              Expanded(
                                flex: 5,
                                child: DropdownWidget(
                                  isCenter: false,
                                  label: "Mês",
                                  icon: Icons.calendar_today,
                                  arrowIcon: Icons.keyboard_arrow_down,
                                  hint: "Selecione o mês",
                                  items: _birthdayBloc.getMonthsList(),
                                  stream: _birthdayBloc.outMonth,
                                  onChanged: _birthdayBloc.changeMonth,
                                ),
                              ),
                              Expanded(
                                flex: 5,
                                child: DropdownWidget(
                                  isCenter: false,
                                  label: "Dia",
                                  arrowIcon: Icons.keyboard_arrow_down,
                                  hint: "Selecione o dia",
                                  items: _birthdayBloc.getDaysList(),
                                  stream: _birthdayBloc.outDay,
                                  onChanged: _birthdayBloc.changeDay,
                                ),
                              ),
                            ],
                          ),
                          DropdownWidget(
                              isCenter: false,
                              label: "Ano de nascimento",
                              icon: Icons.perm_contact_calendar,
                              arrowIcon: Icons.keyboard_arrow_down,
                              hint: "Selecione o ano",
                              items: _birthdayBloc.getYearsList(),
                              stream: _birthdayBloc.outYear,
                              onChanged: _birthdayBloc.changeYear,
                              valueController: 'Não sei'
                          ),

Here is the code that retrieves the data from Firebase when the screen is loaded:


  Future<void> _loadSelectedBirthday(personId) async {
    String _userUid = await _getCurrentUserUid();

    await _firestore.collection('birthdays').document(_userUid).collection('birthdays').document(personId).get()
      .then((document) {
        _nameController.add(document.data["name"]);
        _phoneController.add(document.data["phone"]);
        _emailController.add(document.data["email"]);
        _categoryController.add(document.data["category"]);
        _notificationController.add(document.data["notification"]);
        _monthController.add(document.data["month"]);
        _dayController.add(document.data["day"]);
        _yearController.add(document.data["year"]);

        print(_nameController.value);
        print(_phoneController.value);
        print(_emailController.value);
        print(_categoryController.value);
        print(_notificationController.value);
        print(_monthController.value);
        print(_dayController.value);
        print(_yearController.value);

        _stateController.add(BirthdayState.READY);
      }).catchError((error) {
        print('ERROR => $error');
      });
  }

The output I get from the prints above is:

I/flutter (10907): Person Name
I/flutter (10907): 62999991234
I/flutter (10907): [email protected]
I/flutter (10907): Familiar
I/flutter (10907): No dia
I/flutter (10907): 3
I/flutter (10907): 25
I/flutter (10907): 1996

And here is the print from the app screen:

Birthday submition screen

Upvotes: 0

Views: 1681

Answers (1)

Alex Radzishevsky
Alex Radzishevsky

Reputation: 3768

Looks like you missed TextField initialization with value, that is why field is missing data. TextField can be initialized via its controller property:

...
          return TextField(
            controller: TextEditingController(text: snapshot.data), // <--
            keyboardType: type != null ? type : null,
            onChanged: onChanged,
...

Therefore it could be not the best way to init text field this way in StreamBuilder. Depending on your requirements it could be better to:

  1. make InputField widget stateful
  2. declare TextEditingController field in InputField's State class
  3. subscribe for stream in State and update controller's value or text properties every time stream emits data.

Upvotes: 2

Related Questions