Bagaimana cara memperbarui nilai untuk TextField menggunakan StreamBuilder?

13

Saya punya textfielddan saya menggunakan sqflitebasis data di aplikasi saya. The sqflitememiliki nilai yang saya perlu untuk menetapkan ke sayatextfield

Ini textfieldkode saya

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

Sekarang dalam initstatemetode kelas saya, saya mengambil nilai dari database. Itu menjadi operasi yang tidak sinkron sehingga butuh waktu.

Kelas blok saya memiliki kode seperti berikut

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

jadi segera setelah saya menerima nilai dari database saya sebut berikut

doctorNameChanged("valuefromdatabase");

tetapi saya tidak bisa melihat nilai di bidang teks saya. Juga ada nilai yang ada di basis data saya. Apakah mungkin untuk memperbarui nilai tanpa menggunakan TextEditingControlleratau setState. Saya mencoba untuk menghindari mereka karena kelas saya terbagi dalam banyak chuncks dan terlalu rumit untuk menggunakan salah satu di atas saya telah mencoba menggunakan pendekatan yang sama dengan RadioButtondan CheckBoxdan mereka tampaknya memperbarui dengan benar. Nilai ini juga diperbarui di _doctorName.stream.valuemana ada dalam database tetapi textfieldtidak menunjukkan data apa pun. Saya juga mencoba mengubah warna textfieldjadi tidak ada masalah di sana dan saya bisa melihat apa yang saya ketik.

Saya telah membuat demo kecil aplikasi https://github.com/PritishSawant/demo/tree/master/lib

Alih-alih menggunakan sqflite, saya menggunakan shared preferencestetapi masalahnya tetap ada

Dorongan
sumber
Coba hapus "initialValue: patientHealthFormBloc.doctorNameValue", dan mulai di "initialData" dari StreamBuilder
Stel
@Stel Terima kasih tetapi tidak berhasil
Nudge
Anda dapat menggunakan TextEditingController (text
@ ChinkySight Saya menggunakan Stream untuk menghindari TextEditingController. Aplikasi ini rumit dan menggunakan TextEditingController tidak layak
Nudge
Dalam contoh Anda, Anda tidak menggunakan snapshot sama sekali. Data apa yang Anda harapkan untuk diambil darinya untuk digunakan di TextFormField Anda? Mengapa Anda tidak bisa menggunakan TextEditingController?
João Soares

Jawaban:

4

Oke jadi saya akhirnya menemukan solusi untuk masalah saya.

Berikut ini adalah kode saya, saya baru saja menggunakan SharedPreferencesbukan sqfliteuntuk contoh di bawah ini. Hal yang sama dapat dilakukan dengansqflite

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);
              },
            );
           },
        ),
      ),
    );
  }
}
Dorongan
sumber
Ini solusi yang sangat direkayasa. Saya harap Anda telah menjelaskan apa yang sebenarnya ingin Anda capai pada awalnya alih-alih ingin kami memperbaiki solusi spesifik Anda. Saat saya mengomentari pertanyaan Anda, Anda tampaknya ingin melakukan pembaruan waktu-nyata ke TextField yang mungkin digunakan secara aktif oleh pengguna. Ini sangat aneh dan kemungkinan UX buruk.
João Soares
@ JoãoSoares Bisakah Anda memposting solusi Anda. Saya lebih dari senang untuk memberi hadiah dan menerima solusi Anda jika itu lebih baik daripada milik saya. Saya baru saja memposting solusi yang lebih mudah sehingga semua orang bisa mengerti tetapi pada kenyataannya aplikasi saya membutuhkan sinkronisasi dengan sqflite dan firestore sehingga mungkin terlihat direkayasa untuk Anda
Nudge
Jika Anda bisa menjelaskan mengapa Anda ingin Streaming (memperbarui) nilai TextFieldForm pada saat yang sama pengguna mungkin menggunakannya, saya mungkin dapat membantu Anda. Sinkronisasi dengan SQFlite dan Firestore tidak memiliki keterlibatan dalam klaim saya bahwa solusi yang Anda berikan terlalu direkayasa.
João Soares
@ JoãoSoares Silakan baca pertanyaan lagi.
Sikut
Saya telah membaca pertanyaan beberapa kali dan telah melihat kode yang Anda bagikan di GitHub. Penjelasan Anda berbicara tentang apa yang ingin Anda lakukan dan bagaimana Anda ingin kode itu ditulis. Itu tidak menjelaskan mengapa Anda ingin memiliki TextFormField diisi dengan cara itu dengan Streaming data atau premis untuk perilaku itu.
João Soares
2

Coba pendekatan berikut:

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

beri tahu saya jika Anda membutuhkan lebih banyak bantuan.

Harshvardhan Joshi
sumber
tidak bekerja ...
Sikut
apakah Anda menerima nama baru dalam aliran?
Harshvardhan Joshi
ya tetapi nilainya tidak diperbarui
Nudge
apakah Anda menerima nama baru yang sama builder: (context, snapshot)?
Harshvardhan Joshi
Saat saya mengetik teks, saya menerima teks yang diketik. Pada tahap awal ketika saya mengambil dari db maka itu mencetak nilai db. StreamBuilder bekerja dengan baik dan nilai diperbarui ketika saya mengetik secara manual tetapi tidak memperbarui ketika diambil dari basis data
Nudge
1

Apa yang disarankan dalam komentar saya adalah sesuatu seperti ini:

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

Saya tidak ingin menulis jawaban ini tanpa memahami mengapa Anda tidak ingin menggunakan TextEditingController atau setState. Tetapi ini harus mencapai apa yang Anda inginkan saat menggunakan pola Blok.

João Soares
sumber
Saya memiliki pemikiran ini pada awalnya, tetapi karena pertanyaannya dikutip dan @Nudge bersikeras untuk tidak menggunakan TextEditController, jadi saya membatalkan ide itu. Sangat menyenangkan bahwa hanya dengan menggunakan pengontrol, solusinya menjadi sederhana dan kecil untuk bekerja secara akurat. Kerja bagus.
Harshvardhan Joshi
1
Terima kasih, saya menghargainya. Sayangnya pengguna tampaknya bersikeras untuk tetap pada idenya sendiri dan tidak mencoba untuk menulis solusi yang tepat, karena itu mereka memutuskan untuk tidak mengaitkan respon yang benar atau karunia.
João Soares
Oh baiklah. Lupakan saja.
Harshvardhan Joshi