Wie aktualisiere ich den Wert für TextField mit StreamBuilder?

13

Ich habe eine textfieldund ich benutze sqfliteDatenbank in meiner App. Das sqflitehat einen Wert, den ich meinem zuweisen musstextfield

Hier ist mein textfieldCode

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

Jetzt in der initstateMethode meiner Klasse hole ich Wert aus der Datenbank. Da es sich um eine asynchrone Operation handelt, dauert es einige Zeit.

Meine Blockklasse hat einen Code wie folgt

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

Sobald ich einen Wert aus der Datenbank erhalte, rufe ich Folgendes an

doctorNameChanged("valuefromdatabase");

aber ich kann den Wert in meinem Textfeld nicht sehen. Außerdem ist in meiner Datenbank ein Wert vorhanden. Ist es möglich , den Wert zu aktualisieren , ohne Verwendung TextEditingControlleroder setState. Ich bin ein Versuch , diejenigen zu vermeiden , da meine Klasse in vielen chuncks und viel zu kompliziert unterteilt ist eine der verwenden oben ich mit dem gleichen Ansatz versucht habe , mit RadioButtonund , CheckBoxund sie scheinen richtig zu aktualisieren. Der Wert wird ebenfalls aktualisiert, _doctorName.stream.valueder in der Datenbank vorhanden ist, aber textfieldkeine Daten anzeigt. Außerdem habe ich versucht, die Farbe von zu ändern, textfielddamit es dort kein Problem gibt und ich sehen kann, was ich tippe.

Ich habe eine kleine Demo der App https://github.com/PritishSawant/demo/tree/master/lib erstellt

Anstatt zu verwenden sqflite, verwende ich, shared preferencesaber das Problem bleibt bestehen

Schubs
quelle
Versuchen Sie, "initialValue: patientHealthFormBloc.doctorNameValue" zu entfernen, und starten Sie es in den "initialData" aus dem StreamBuilder
Stel
@Stel Danke, funktioniert aber nicht
Nudge
Sie können den TextEditingController (text
@ChinkySight Ich verwende Stream, um TextEditingController zu vermeiden. Die App ist kompliziert und die Verwendung von TextEditingController ist nicht möglich
Nudge
In Ihrem Beispiel verwenden Sie den Schnappschuss überhaupt nicht. Welche Daten erwarten Sie daraus zu extrahieren, um sie in Ihrem TextFormField zu verwenden? Warum können Sie keinen TextEditingController verwenden?
João Soares

Antworten:

4

OK, also habe ich endlich die Lösung für mein Problem gefunden.

Das Folgende ist mein Code, den ich gerade SharedPreferencesanstelle des sqflitefolgenden Beispiels verwendet habe. Dasselbe kann mit getan werdensqflite

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);
              },
            );
           },
        ),
      ),
    );
  }
}
Schubs
quelle
Dies ist eine extrem überentwickelte Lösung. Ich wünschte, Sie hätten erklärt, was genau Sie ursprünglich erreichen wollten, anstatt dass wir Ihre spezifische Lösung reparieren sollten. Während ich Ihre Frage kommentierte, möchten Sie anscheinend Echtzeit-Updates für ein TextField durchführen, das möglicherweise vom Benutzer aktiv verwendet wird. Dies ist sehr seltsam und wahrscheinlich schlechte UX.
João Soares
@ JoãoSoares Kannst du deine Lösung posten? Ich bin mehr als glücklich, das Kopfgeld zu vergeben und Ihre Lösung zu akzeptieren, wenn sie besser ist als meine. Ich habe gerade eine einfachere Lösung veröffentlicht, damit jeder sie verstehen kann, aber in Wirklichkeit muss meine App sowohl mit sqflite als auch mit firestore synchronisiert werden, damit sie für Sie überarbeitet wird
Nudge,
Wenn Sie erklären können, warum Sie den Wert einer TextFieldForm streamen (aktualisieren) möchten, während der Benutzer sie möglicherweise verwendet, kann ich Ihnen möglicherweise helfen. Die Synchronisierung mit SQFlite und Firestore hat nichts mit meiner Behauptung zu tun, dass die von Ihnen vorgestellte Lösung überentwickelt ist.
João Soares
@ JoãoSoares Bitte lesen Sie die Frage noch einmal.
Nudge
Ich habe die Frage bereits mehrmals gelesen und den Code gesehen, den Sie auf GitHub geteilt haben. Ihre Erklärung spricht davon, was Sie tun möchten und wie der Code geschrieben werden soll. Es wird nicht erklärt, warum ein TextFormField auf diese Weise mit Daten-Streaming oder der Voraussetzung für dieses Verhalten gefüllt werden soll.
João Soares
2

Versuchen Sie den folgenden Ansatz:

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

Lassen Sie mich wissen, wenn Sie weitere Hilfe benötigen.

Harshvardhan Joshi
quelle
funktioniert nicht ...
Nudge
Erhalten Sie neue Namen im Stream?
Harshvardhan Joshi
Ja, aber der Wert wird nicht aktualisiert
Nudge
Erhalten Sie die gleichen neuen Namen in builder: (context, snapshot)?
Harshvardhan Joshi
Wenn ich einen Text eingebe, erhalte ich den eingegebenen Text. In der Anfangsphase, wenn ich von der Datenbank abrufe, wird der Datenbankwert gedruckt. Der StreamBuilder funktioniert einwandfrei und der Wert wird aktualisiert, wenn ich manuell tippe, aber er wird nicht aktualisiert, wenn er aus der Datenbank abgerufen wird
Nudge
1

Was in meinen Kommentaren vorgeschlagen wurde, war ungefähr so:

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

Ich wollte diese Antwort nicht schreiben, ohne zu verstehen, warum Sie keinen TextEditingController oder einen setState verwenden wollten. Dies sollte jedoch das erreichen, was Sie möchten, wenn Sie das Blockmuster verwenden.

João Soares
quelle
Ich hatte diesen Gedanken am Anfang, aber da die zitierte Frage und @Nudge darauf bestanden, das nicht zu verwenden TextEditController, kratzte ich diese Idee. Es ist großartig, dass nur durch die Verwendung des Controllers die Lösung einfach und klein wird, um genau zu arbeiten. Gut gemacht.
Harshvardhan Joshi
1
Danke, ich weiß das zu schätzen. Leider schien der Benutzer fest entschlossen zu sein, an seiner eigenen Idee festzuhalten und nicht zu versuchen, eine richtige Lösung zu schreiben, da er sich entschied, nicht die richtige Antwort oder das Kopfgeld zuzuweisen.
João Soares
Oh ok. Egal Dann.
Harshvardhan Joshi