Come aggiornare il valore per TextField utilizzando StreamBuilder?


13

Ho un textfielde sto usando il sqflitedatabase nella mia app. Il sqfliteha un valore che ho bisogno di assegnare al miotextfield

Ecco il mio textfieldcodice

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

Ora nel initstatemetodo della mia classe, sto recuperando valore dal database. Essendo un'operazione asincrona, ci vuole tempo.

La mia classe di blocco ha un codice come segue

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

così appena ricevo valore dal database chiamo seguente

doctorNameChanged("valuefromdatabase");

ma non riesco a vedere il valore nel mio campo di testo. Inoltre c'è un valore presente nel mio database. È possibile aggiornare il valore senza usare TextEditingControllero setState. Sto cercando di evitare quelli perché la mia classe è divisa in molti pezzi e troppo complicata per usare uno dei precedenti con cui ho provato a utilizzare lo stesso approccio RadioButtone CheckBoxe sembrano aggiornarsi correttamente. Il valore viene anche aggiornato in _doctorName.stream.valuecui è presente nel database ma textfieldnon mostra alcun dato. Inoltre ho provato a cambiare il colore ditextfield quindi non c'è nessun problema e sono in grado di vedere quello che scrivo.

Ho realizzato una piccola demo dell'app https://github.com/PritishSawant/demo/tree/master/lib

Invece di usare sqflite, sto usando shared preferencesma il problema persiste


Prova a rimuovere "initialValue: patientHealthFormBloc.doctorNameValue" e avvialo in "initialData" da StreamBuilder
Stel

@Stel Grazie ma non funziona
Nudge

È possibile utilizzare TextEditingController (testo

@ChinkySight Sto usando Stream per evitare TextEditingController. L'app è complicata e l'utilizzo di TextEditingController non è fattibile
Nudge

Nel tuo esempio non stai affatto usando l'istantanea. Quali dati prevedi di estrarre da esso per utilizzare TextFormField? Perché non puoi usare un TextEditingController?
João Soares,

Risposte:


4

OK, quindi ho finalmente trovato la soluzione al mio problema.

Di seguito è riportato il mio codice, ho appena usato SharedPreferencesinvece che sqfliteper l'esempio di seguito. È possibile fare lo stessosqflite

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);
              },
            );
           },
        ),
      ),
    );
  }
}

Questa è una soluzione estremamente ingegnerizzata. Vorrei che tu avessi spiegato che cosa esattamente volevi ottenere originariamente invece di volerci che risolvessimo la tua soluzione specifica. Come ho commentato la tua domanda, sembra che tu voglia fare aggiornamenti in tempo reale a un campo di testo che può essere utilizzato attivamente dall'utente. Questa è una UX molto strana e probabilmente cattiva.
João Soares,

@ JoãoSoares Puoi pubblicare la tua soluzione. Sono più che felice di assegnare la generosità e accettare la tua soluzione se è migliore della mia. Ho appena pubblicato una soluzione più semplice in modo che tutti possano capire ma in realtà la mia app richiede la sincronizzazione con sqflite e il firestore in modo che possa sembrare troppo progettata per te
Nudge

Se riesci a spiegare perché desideri trasmettere (aggiornare) il valore di un oggetto TextField nello stesso momento in cui l'utente potrebbe utilizzarlo, potrei essere in grado di aiutarti. La sincronizzazione con SQFlite e Firestore non ha alcun coinvolgimento nella mia affermazione che la soluzione presentata è troppo ingegnerizzata.
João Soares,

@ JoãoSoares Leggi di nuovo la domanda.
Spingi il

Ho già letto la domanda più volte e ho visto il codice che hai condiviso su GitHub. La tua spiegazione parla di cosa vuoi fare e di come vuoi scrivere il codice. Non spiega perché si desidera che un TextFormField venga riempito in quel modo con lo streaming di dati o le premesse per quel comportamento.
João Soares,

2

Prova il seguente approccio:

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);
      },
    ...

fammi sapere se hai bisogno di più aiuto.


non funziona ...
Spingi il

stai ricevendo nuovi nomi in streaming?
Harshvardhan Joshi

sì, ma il valore non viene aggiornato
Nudge

stai ricevendo gli stessi nuovi nomi in builder: (context, snapshot)?
Harshvardhan Joshi

Quando scrivo un testo, ricevo il testo digitato. Nella fase iniziale quando sto recuperando da db, allora sta stampando il valore db. StreamBuilder funziona bene e il valore si aggiorna quando scrivo manualmente ma non si aggiorna quando viene recuperato dal database
Nudge

1

Ciò che stava suggerendo nei miei commenti era qualcosa del genere:

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);
        },
      ],
    ),
  );
}

Non volevo scrivere questa risposta senza capire perché non volevi usare un TextEditingController o un setState. Ma questo dovrebbe ottenere quello che vuoi mentre usi il modello Bloc.


Ho avuto questo pensiero all'inizio, ma dal momento che la domanda citava e @Nudge stava insistendo sul non usare il TextEditController, quindi ho raschiato quell'idea . È bello che solo usando il controller la soluzione diventi semplice e piccola per funzionare in modo accurato. Ottimo lavoro.
Harshvardhan Joshi,

1
Grazie l'ho apprezzato. Sfortunatamente l'utente sembrava irremovibile di attenersi alla propria idea e non tentare di scrivere una soluzione adeguata, in quanto tale ha deciso di non attribuire la risposta corretta o la generosità.
João Soares,

Oh ok. Non importa allora.
Harshvardhan Joshi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.