Comment mettre à jour la valeur de TextField à l'aide de StreamBuilder?

13

j'ai un textfield etsqflite base de données dans mon application. Le sqflitea une valeur que je dois attribuer à montextfield

Voici mon textfieldcode

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

Maintenant dans le initstate méthode de ma classe, je récupère la valeur de la base de données. Il s'agit d'une opération asynchrone donc cela prend du temps.

Ma classe de bloc a un code comme suit

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

donc dès que je reçois de la valeur de la base de données j'appelle suivant

doctorNameChanged("valuefromdatabase");

mais je ne peux pas voir la valeur dans mon champ de texte. Il y a aussi une valeur présente dans ma base de données. Est-il possible de mettre à jour la valeur sans utiliser TextEditingControllerou setState. I ma essayant d'éviter ceux que ma classe est divisée en beaucoup de chuncks et trop compliqué à utiliser tout de ce qui précède , je l' ai essayé d' utiliser même approche avec RadioButtonet CheckBoxet ils semblent mettre à jour correctement. La valeur est également mise à jour dans _doctorName.stream.valuelaquelle est présente dans la base de données mais textfieldn'affiche aucune donnée. J'ai également essayé de changer la couleur de textfielddonc il n'y a pas de problème et je peux voir ce que je tape.

J'ai fait une petite démo de l'application https://github.com/PritishSawant/demo/tree/master/lib

Au lieu d'utiliser sqflite, j'utilise shared preferencesmais le problème persiste

Coup de coude
la source
Essayez de supprimer "initialValue: patientHealthFormBloc.doctorNameValue" et démarrez-le dans les "initialData" du StreamBuilder
Stel
@Stel Merci mais ne fonctionne pas
Nudge
Vous pouvez utiliser TextEditingController (text
@ChinkySight J'utilise Stream pour éviter TextEditingController. L'application est compliquée et l'utilisation de TextEditingController n'est pas possible
Nudge
Dans votre exemple, vous n'utilisez pas du tout l'instantané. Quelles données pensez-vous en extraire pour les utiliser dans votre TextFormField? Pourquoi ne pouvez-vous pas utiliser un TextEditingController?
João Soares

Réponses:

4

OK, j'ai finalement trouvé la solution à mon problème.

Voici mon code, je viens d'utiliser à la SharedPreferencesplace de sqflitel'exemple ci-dessous. La même chose peut être faite avecsqflite

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);
              },
            );
           },
        ),
      ),
    );
  }
}
Coup de coude
la source
C'est une solution extrêmement surdimensionnée. Je souhaite que vous ayez expliqué exactement ce que vous vouliez réaliser à l'origine au lieu de vouloir que nous corrigions votre solution spécifique. Comme je l'ai commenté sur votre question, vous semblez vouloir faire des mises à jour en temps réel d'un TextField qui peut être utilisé activement par l'utilisateur. C'est UX très étrange et probablement mauvais.
João Soares
@ JoãoSoares Pouvez-vous publier votre solution. Je suis plus qu'heureux d'attribuer la prime et d'accepter votre solution si elle est meilleure que la mienne. Je viens de publier une solution plus simple pour que tout le monde puisse comprendre, mais en réalité, mon application nécessite une synchronisation avec sqflite ainsi qu'avec firestore afin qu'elle puisse être conçue par vous
Nudge
Si vous pouvez expliquer pourquoi vous souhaitez diffuser (mettre à jour) la valeur d'un TextFieldForm en même temps que l'utilisateur l'utilise, je pourrai peut-être vous aider. La synchronisation avec SQFlite et Firestore n'a aucune implication dans mon affirmation selon laquelle la solution que vous avez présentée est sur-conçue.
João Soares
@ JoãoSoares Veuillez relire la question.
Nudge
J'ai déjà lu la question plusieurs fois et j'ai vu le code que vous avez partagé sur GitHub. Votre explication parle de ce que vous voulez faire et de la façon dont vous voulez que le code soit écrit. Il n'explique pas pourquoi vous souhaitez qu'un TextFormField soit rempli de cette manière avec le streaming de données ou la prémisse de ce comportement.
João Soares
2

Essayez l'approche suivante:

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

faites-moi savoir si vous avez besoin de plus d'aide.

Harshvardhan Joshi
la source
ne fonctionne pas ...
Nudge
recevez-vous de nouveaux noms dans le flux?
Harshvardhan Joshi
oui mais la valeur n'est pas mise à jour
Nudge
recevez-vous les mêmes nouveaux noms builder: (context, snapshot)?
Harshvardhan Joshi
Lorsque je tape un texte, je reçois le texte tapé. Au stade initial quand j'aller chercher de db il imprime le db StreamBuilder travaille valeur fine et les mises à jour de valeur quand je taper manuellement mais il ne met pas à jour quand il est extrait de la base de données
Nudge
1

Ce qui suggérait dans mes commentaires était quelque chose comme ceci:

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

Je ne voulais pas écrire cette réponse sans comprendre pourquoi vous ne vouliez pas utiliser un TextEditingController ou un setState. Mais cela devrait atteindre ce que vous voulez tout en utilisant le modèle Bloc.

João Soares
la source
J'avais cette pensée au début, mais puisque la question citée et @Nudge insistait pour ne pas utiliser le TextEditController, j'ai donc gratté cette idée. C'est formidable que ce n'est qu'en utilisant le contrôleur que la solution devient simple et petite pour fonctionner avec précision. Bon travail.
Harshvardhan Joshi
1
Merci j'apprécie. Malheureusement, l'utilisateur semblait obstiné à s'en tenir à sa propre idée et à ne pas essayer d'écrire une solution appropriée, en tant que tel, il a décidé de ne pas attribuer la bonne réponse ou la prime.
João Soares
Ah d'accord. Pas de soucis alors.
Harshvardhan Joshi