Как обновить значение для TextField с помощью StreamBuilder?

13

У меня есть, textfieldи я использую sqfliteбазу данных в моем приложении. sqfliteИмеет значение , которое мне нужно присвоить мойtextfield

Вот мой textfieldкод

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

Теперь в initstateметоде моего класса я выбираю значение из базы данных. Это асинхронная операция, поэтому она требует времени.

Мой класс блоков имеет следующий код

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

поэтому, как только я получу значение из базы данных, я вызываю следующее

doctorNameChanged("valuefromdatabase");

но я не вижу значения в моем текстовом поле. Также есть значение, присутствующее в моей базе данных. Можно ли обновить значение без использования TextEditingControllerили setState. Я ма пытаюсь избежать тех , как мой класса делится на много chuncks и слишком сложен , чтобы использовать любого из вышеперечисленного я попытался использовать тот же подход , с RadioButtonи CheckBoxи они , кажется , чтобы обновить должным образом. Также обновляется значение, в _doctorName.stream.valueкотором присутствует в базе данных, но textfieldне показывает никаких данных. Кроме того, я попытался изменить цвет, textfieldтак что нет проблем, так как я могу видеть, что я печатаю.

Я сделал небольшую демонстрацию приложения https://github.com/PritishSawant/demo/tree/master/lib

Вместо того, чтобы использовать sqflite, я использую, shared preferencesно проблема сохраняется

слегка подталкивать локтем
источник
Попробуйте удалить «InitialValue: patientHealthFormBloc.doctorNameValue», и запустить его в «initialData» из StreamBuilder
Stel
@Stel Спасибо, но не работает
подтолкни
Вы можете использовать TextEditingController (text
@ChinkySight Я использую Stream, чтобы избежать TextEditingController. Приложение является сложным, и использование TextEditingController не представляется возможным
подтолкнуть
В вашем примере вы вообще не используете снимок. Какие данные вы ожидаете извлечь из него для использования в вашем TextFormField? Почему вы не можете использовать TextEditingController?
Жоао Соареш

Ответы:

4

Итак, я наконец нашел решение своей проблемы.

Ниже приведен мой код, который я только что использовал SharedPreferencesвместо sqfliteприведенного ниже примера. То же самое можно сделать с помощью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);
              },
            );
           },
        ),
      ),
    );
  }
}
слегка подталкивать локтем
источник
Это чрезвычайно сложное решение. Хотелось бы, чтобы вы объяснили, чего именно вы хотели достичь изначально, вместо того, чтобы попросить нас исправить ваше конкретное решение. Как я прокомментировал ваш вопрос, вы, похоже, хотите в режиме реального времени обновлять TextField, который может активно использоваться пользователем. Это очень странный и, вероятно, плохой UX.
Жоао Соареш
@ JoãoSoares Можете ли вы опубликовать свое решение. Я более чем рад присуждать награду и принять ваше решение, если оно лучше моего. Я только что опубликовал более простое решение, чтобы все могли понять, но на самом деле мое приложение требует синхронизации с sqflite, а также с firestore, чтобы оно могло выглядеть специально для вас
Nudge
Если вы можете объяснить, почему вы хотите передавать (обновлять) значение TextFieldForm в то же время, когда пользователь может его использовать, я могу вам помочь. Синхронизация с SQFlite и Firestore не имеет никакого отношения к моему утверждению о том, что представленное вами решение является чрезмерно разработанным.
Жоао Соареш
@ JoãoSoares Пожалуйста, прочитайте вопрос еще раз.
подтолкнуть
Я уже несколько раз читал вопрос и видел код, которым вы поделились на GitHub. Ваше объяснение говорит о том, что вы хотите сделать и как вы хотите, чтобы код был написан. Это не объясняет, почему вы хотите, чтобы TextFormField заполнялся таким образом с помощью Streaming data или предпосылки для такого поведения.
Жоао Соареш
2

Попробуйте следующий подход:

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

Дай мне знать, если тебе еще понадобится помощь.

Харшвардхан Джоши
источник
не работает ...
подтолкнуть
вы получаете новые имена в потоке?
Харшвардхан Джоши
да, но значение не обновляется
подтолкнуть
вы получаете те же новые имена в builder: (context, snapshot)?
Харшвардхан Джоши
Когда я набираю текст, я получаю набранный текст. На начальном этапе, когда я выбираю из БД, он печатает значение БД. StreamBuilder работает нормально, и значение обновляется, когда я печатаю вручную, но не обновляется, когда оно выбирается из базы данных
Сдвиг
1

То, что предлагалось в моих комментариях, было примерно таким:

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

Я не хотел писать этот ответ, не понимая, почему вы не хотите использовать TextEditingController или setState. Но это должно достичь того, что вы хотите при использовании шаблона Bloc.

Жоао Соареш
источник
У меня была эта мысль в начале, но так как вопрос процитирован, а @Nudge настаивал на том TextEditController, чтобы не использовать , поэтому я отказался от этой идеи. Замечательно, что только с помощью контроллера решение становится простым и маленьким для точной работы. Отличная работа.
Харшвардхан Джоши
1
Спасибо, я ценю это. К сожалению, пользователь казался непреклонным, придерживаясь своей собственной идеи и не пытаясь написать правильное решение, так как они решили не приписывать правильный ответ или вознаграждение.
Жоао Соареш
Ох, ну ладно. Тогда не важно.
Харшвардхан Джоши