Як оновити значення для 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але проблема зберігається


Спробуйте видалити "початкову валью: patiHealthFormBloc.doctorNameValue", і запустіть її в "початкові дані" з StreamBuilder
Stel

@Stel Дякую, але не працює
Наготуйте

Ви можете використовувати TextEditingController (текст

@ChinkySight Я використовую Stream, щоб уникнути TextEditingController. Додаток є складним, і використання TextEditingController не здійснено
Nudge

У вашому прикладі ви зовсім не використовуєте знімок. Які дані ви очікуєте отримати з них для використання у вашому 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);
              },
            );
           },
        ),
      ),
    );
  }
}

Це надзвичайно розроблене рішення. Я б хотів, щоб ви пояснили, чого саме ви хотіли досягти спочатку, а не бажаєте, щоб ми виправили ваше конкретне рішення. Коли я коментував ваше запитання, ви, схоже, хочете оновлювати текстове поле в режимі реального часу, яке користувач може активно використовувати. Це дуже дивно і, ймовірно, погано UX.
Жоао Соарес

@ JoãoSoares Чи можете ви розмістити своє рішення. Я більш ніж радий нагородити нагороду і прийняти ваше рішення, якщо воно краще, ніж моє. Я щойно опублікував більш просте рішення, щоб кожен міг зрозуміти, але насправді моє додаток вимагає синхронізації з sqflite, а також firestore, щоб воно могло виглядати по-інженерськи для вас
Nudge

Якщо ви можете пояснити, чому ви хочете передати (оновити) значення TextFieldForm в той же час, коли користувач може його використовувати, я можу вам допомогти. Синхронізація з SQFlite та Firestore не причетна до мого твердження про те, що представлене вами рішення є надмірно розробленим.
Жоао Соарес

@ JoãoSoares Будь ласка, прочитайте питання ще раз.
Нудьга

Я вже кілька разів читав питання і бачив код, яким ви поділилися на GitHub. Ваше пояснення говорить про те, що ви хочете зробити і як ви хочете написати код. Це не пояснює, чому ви хочете, щоб TextFormField заповнювався таким чином потоковою передачею даних або передумовою для такої поведінки.
Жоао Соарес

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

дайте мені знати, якщо вам потрібна додаткова допомога.


не працює ...
Нудьга

Ви отримуєте нові імена в потоці?
Харшвардхан Джоші

так, але значення не оновлюється
Nudge

ви отримуєте такі ж нові імена в builder: (context, snapshot)?
Харшвардхан Джоші

Коли я набираю текст, я отримую набраний текст. На початковому етапі, коли я отримую з db, тоді він друкує значення db. StreamBuilder працює нормально, і значення оновлюється, коли я вводя вручну, але воно не оновлюється, коли воно отримується з бази даних
Nudge

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. Але для цього слід досягти бажаного, використовуючи блок-схему.


Я подумав про це на початку, але оскільки питання, яке цитується, і @Nudge наполягав на тому, щоб не використовувати цю програму TextEditController, тож я вичесав цю ідею. Чудово, що лише використовуючи контролер, рішення стає простим і малим, щоб точно працювати. Чудова робота.
Харшвардхан Джоші

1
Дякую, я ціную це. На жаль, користувач здавався неприхильним дотримуватися власної ідеї та не намагатися написати належне рішення, тому вони вирішили не приписувати правильну відповідь чи щедрість.
Жоао Соарес

О, гаразд. Неважливо, тоді.
Харшвардхан Джоші
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.