¿Cómo actualizar el valor de TextField usando StreamBuilder?

13

Tengo una textfieldy estoy usando la sqflitebase de datos en mi aplicación. El sqflitetiene un valor que necesito para asignar a mitextfield

Aqui esta mi textfieldcodigo

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

Ahora en el initstatemétodo de mi clase, estoy obteniendo valor de la base de datos. Al ser una operación asincrónica, lleva tiempo.

Mi clase de bloque tiene un código como el siguiente

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

tan pronto como recibo el valor de la base de datos, llamo a continuación

doctorNameChanged("valuefromdatabase");

pero no puedo ver el valor en mi campo de texto. También hay un valor presente en mi base de datos. ¿Es posible actualizar el valor sin usar TextEditingControllero setState? I m tratando de evitar aquellos como mi clase se divide en muchos de los desconchados y demasiado complicado de utilizar cualquiera de los anteriores He intentado usar mismo enfoque con RadioButtony CheckBoxy parece que actualizar correctamente. El valor también se actualiza en el _doctorName.stream.valueque está presente en la base de datos pero textfieldno muestra ningún dato. También intenté cambiar el color de textfieldmodo que no haya ningún problema allí, así como puedo ver lo que escribo.

Hice una pequeña demostración de la aplicación https://github.com/PritishSawant/demo/tree/master/lib

En lugar de usar sqflite, estoy usando shared preferencespero el problema persiste

Empujar
fuente
Intente eliminar "initialValue: patientHealthFormBloc.doctorNameValue" e inícielo en "initialData" desde StreamBuilder
Stel
@Stel Gracias pero no funciona
Empuja el
Puede usar el TextEditingController (text
@ChinkySight Estoy usando Stream para evitar TextEditingController. La aplicación es complicada y el uso de TextEditingController no es factible
Empuje el
En su ejemplo, no está utilizando la instantánea en absoluto. ¿Qué datos espera extraer de él para usar en su TextFormField? ¿Por qué no puedes usar un TextEditingController?
João Soares

Respuestas:

4

OK, así que finalmente encontré la solución a mi problema.

El siguiente es mi código, que acabo de usar en SharedPreferenceslugar del sqflitesiguiente ejemplo. Lo mismo se puede hacer consqflite

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);
              },
            );
           },
        ),
      ),
    );
  }
}
Empujar
fuente
Esta es una solución extremadamente sobre diseñada. Desearía que me hubieras explicado exactamente qué querías lograr originalmente en lugar de querer que solucionemos tu solución específica. Como comenté sobre su pregunta, parece que desea realizar actualizaciones en tiempo real de un TextField que el usuario puede estar utilizando activamente. Esto es muy extraño y probablemente sea una mala experiencia de usuario.
João Soares
@ JoãoSoares ¿Puede publicar su solución? Estoy más que feliz de otorgar la recompensa y aceptar su solución si es mejor que la mía. Acabo de publicar una solución más fácil para que todos puedan entender, pero en realidad mi aplicación requiere sincronización con sqflite y firestore, por lo que puede parecer que está diseñada para ti
Empuja el
Si puede explicar por qué desea transmitir (actualizar) el valor de un TextFieldForm al mismo tiempo que el usuario podría estar usándolo, es posible que pueda ayudarlo. La sincronización con SQFlite y Firestore no tiene nada que ver con mi afirmación de que la solución que presentó está sobredimensionada.
João Soares
@ JoãoSoares Por favor lea la pregunta nuevamente.
Empujar el
Ya leí la pregunta varias veces y vi el código que compartiste en GitHub. Su explicación habla de lo que quiere hacer y cómo quiere que se escriba el código. No explica por qué desea que un TextFormField se complete de esa manera con la transmisión de datos o la premisa de ese comportamiento.
João Soares
2

Pruebe el siguiente enfoque:

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

dejame saber si necesitas mas ayuda.

Harshvardhan Joshi
fuente
no funciona ...
Empujar
¿Estás recibiendo nuevos nombres en stream?
Harshvardhan Joshi
Sí, pero el valor no está siendo actualizado
Empujar
¿Estás recibiendo los mismos nombres nuevos builder: (context, snapshot)?
Harshvardhan Joshi
Cuando escribo un texto, recibo el texto escrito. En la etapa inicial cuando recupero datos de db, imprime el valor de db. StreamBuilder funciona bien y el valor se actualiza cuando escribo manualmente, pero no se actualiza cuando se recupera de la base de datos
Empuje el
1

Lo que sugería en mis comentarios era algo como esto:

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

No quería escribir esta respuesta sin entender por qué no quería usar un TextEditingController o un setState. Pero esto debería lograr lo que desea mientras usa el patrón Bloc.

João Soares
fuente
Tuve este pensamiento al principio, pero como la pregunta citada y @Nudge insistía en no usar el TextEditController, entonces descarté esa Idea. Es genial que solo al usar el controlador la solución se vuelva simple y pequeña para trabajar con precisión. Gran trabajo.
Harshvardhan Joshi
1
Gracias lo aprecio. Desafortunadamente, el usuario parecía inflexible en apegarse a su propia idea y no intentar escribir una solución adecuada, por lo que decidió no atribuir la respuesta correcta o la recompensa.
João Soares
Ah, vale. Olvidalo entonces.
Harshvardhan Joshi