Como atualizar o valor do TextField usando o StreamBuilder?

13

Eu tenho um textfielde estou usando sqflitebanco de dados no meu aplicativo. O sqflitetem um valor que eu preciso atribuir ao meutextfield

Aqui está o meu textfieldcódigo

 StreamBuilder<String>(
    stream: patientHealthFormBloc.doctorName,
    builder: (context, snapshot) {
      return TextFormField(
        initialValue: patientHealthFormBloc.doctorNameValue,
        onChanged: (value) {
          patientHealthFormBloc.doctorNameChanged(value);
        },
        ...

Agora, no initstatemétodo da minha classe, estou buscando valor do banco de dados. Sendo uma operação assíncrona, leva tempo.

Minha classe de bloco tem um código como segue

Function(String) get doctorNameChanged => _doctorName.sink.add;

Então, assim que eu receber valor do banco de dados eu chamo a seguir

doctorNameChanged("valuefromdatabase");

mas não consigo ver o valor no meu campo de texto. Também há um valor presente no meu banco de dados. É possível atualizar o valor sem usar TextEditingControllerou setState. I ma tentando evitar aqueles como a minha turma é dividida em lote de chuncks e muito complicado de usar qualquer um dos acima Eu tentei usar mesma abordagem RadioButtone CheckBoxe eles parecem atualizar corretamente. O valor também é atualizado, no _doctorName.stream.valuequal está presente no banco de dados, mas textfieldnão mostra nenhum dado. Também tentei mudar de cor textfieldpara que não haja problema lá, assim como eu sou capaz de ver o que digito.

Fiz uma pequena demonstração do aplicativo https://github.com/PritishSawant/demo/tree/master/lib

Em vez de usar sqflite, estou usando, shared preferencesmas o problema persiste

Nudge
fonte
Tente remover "initialValue: PatientHealthFormBloc.doctorNameValue" e inicie-o nos "initialData" do StreamBuilder
Stel
@Stel Obrigado, mas não funciona
Nudge
Você pode usar o TextEditingController (text
@ChinkySight Estou usando o Stream para evitar o TextEditingController. O aplicativo é complicado e o uso do TextEditingController não é viável
Nudge
No seu exemplo, você não está usando o instantâneo. Quais dados você espera extrair para usar no TextFormField? Por que você não pode usar um TextEditingController?
João Soares

Respostas:

4

OK, então finalmente encontrei a solução para o meu problema.

A seguir, é apresentado o meu código, que acabei de usar em SharedPreferencesvez do sqfliteexemplo abaixo.sqflite

class _MyHomePageState extends State<MyHomePage> {

  MyBloc myBloc = MyBloc();
  TextEditingController myController = TextEditingController();

  @override
  void dispose() {
    myBloc?.close();
    myController?.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    AppPreferences.setString("data", "this is my data");
    AppPreferences.getString("data").then((value){
      myBloc.dataChanged(value);
    });
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: StreamBuilder(
          stream: myBloc.data,
           builder: (context,snapshot){

            debugPrint(snapshot.data);
            myController.value = myController.value.copyWith(text: myBloc.dataValue);

            return TextFormField(
              controller: myController,
              onChanged: (value){
                myBloc.dataChanged(value);
              },
            );
           },
        ),
      ),
    );
  }
}
Nudge
fonte
Esta é uma solução extremamente projetada. Eu gostaria que você tivesse explicado o que exatamente você queria alcançar originalmente, em vez de querer que consertássemos sua solução específica. Como eu comentei sua pergunta, você parece querer atualizar em tempo real um TextField que pode estar sendo usado ativamente pelo usuário. É um UX muito estranho e provavelmente ruim.
João Soares
@ JoãoSoares Você pode postar sua solução. Estou mais do que feliz em conceder a recompensa e aceitar sua solução, se for melhor que a minha. Acabei de publicar uma solução mais fácil para que todos possam entender, mas, na realidade, meu aplicativo requer sincronização com sqflite e firestore para que possa parecer mais projetado para você
Nudge
Se você puder explicar por que deseja transmitir (atualizar) o valor de um TextFieldForm ao mesmo tempo em que o usuário o estiver usando, talvez eu possa ajudá-lo. A sincronização com o SQFlite e o Firestore não tem nenhum envolvimento em minha alegação de que a solução que você apresentou foi projetada em excesso.
João Soares
@ JoãoSoares Por favor, leia a pergunta novamente.
Nudge
Já li a pergunta várias vezes e vi o código que você compartilhou no GitHub. Sua explicação fala sobre o que você deseja fazer e como deseja que o código seja escrito. Ele não explica por que você deseja que um TextFormField seja preenchido dessa maneira com o Streaming de dados ou a premissa para esse comportamento.
João Soares
2

Tente a seguinte abordagem:

StreamBuilder<String>(
  stream: patientHealthFormBloc.doctorName,
  builder: (context, snapshot) {
    String doctorName = patientHealthFormBloc.doctorNameValue;
    if(snapshot.hasData){
      doctorName = snapshot.data/*(your name string from the stream)*/;
    } 
    return TextFormField(
      initialValue: doctorName,
      onChanged: (value) {
        patientHealthFormBloc.doctorNameChanged(value);
      },
    ...

entre em contato se precisar de mais ajuda.

Harshvardhan Joshi
fonte
não funciona ...
Nudge
você está recebendo novos nomes no stream?
Harshvardhan Joshi
sim, mas o valor não está sendo atualizado
Nudge
você está recebendo os mesmos novos nomes builder: (context, snapshot)?
Harshvardhan Joshi
Quando digito um texto, recebo o texto digitado. No estágio inicial, quando eu busco no banco de dados, ele está imprimindo o valor do banco de dados. O StreamBuilder está funcionando bem e o valor é atualizado quando eu digito manualmente, mas ele não é atualizado quando é buscado no banco de dados
Nudge
1

O que estava sugerindo nos meus comentários era algo assim:

TextEditingController _textEditingController = TextEditingController();

@override
void initState() {
  patientHealthFormBloc.doctorName.listen((snapshot){
    setState((){
      _textEditingController.text = snapshot;
    });
  });
  super.initState();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Column(
      children: <Widget>[
      TextFormField(
        controller: _textEditingController,
        onChanged: (value) {
          patientHealthFormBloc.doctorNameChanged(value);
        },
      ],
    ),
  );
}

Eu não queria escrever esta resposta sem entender por que você não queria usar um TextEditingController ou um setState. Mas isso deve alcançar o que você deseja ao usar o padrão Bloc.

João Soares
fonte
Eu tinha esse pensamento no começo, mas como a pergunta citada e o @Nudge insistiam em não usar o TextEditController, então raspei essa ideia. É ótimo que apenas usando o controlador a solução se torne simples e pequena para funcionar com precisão. Bom trabalho.
Harshvardhan Joshi
11
Obrigado, agradeço. Infelizmente, o usuário parecia inflexível em seguir sua própria idéia e não tentar escrever uma solução adequada; portanto, decidiu não atribuir a resposta correta ou a recompensa.
João Soares
Ah, tudo bem. Deixa pra lá então.
Harshvardhan Joshi