Как обновить значение для 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
Спасибо, я ценю это. К сожалению, пользователь казался непреклонным, придерживаясь своей собственной идеи и не пытаясь написать правильное решение, так как они решили не приписывать правильный ответ или вознаграждение.
Жоао Соареш

Ох, ну ладно. Тогда не важно.
Харшвардхан Джоши
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.