Як оновити значення для 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.