StreamBuilderを使用してTextFieldの値を更新する方法は?


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私のクラスのメソッドで、データベースから値をフェッチしています。非同期操作なので時間がかかります。

私のblocクラスには次のようなコードがあります

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

データベースから値を受け取ったらすぐに次を呼び出します

doctorNameChanged("valuefromdatabase");

テキストフィールドに値が表示されません。また、私のデータベースには値が存在します。それは使用せずに値を更新することは可能ですTextEditingControllersetState。私は私のクラスは、あまりにも、私はと同じアプローチを使用してみましたが、上記のいずれかを使用するには複雑chuncks及び方法の多くに分割されたとして、それらを避けるためにしようとミリアンペアRadioButtonCheckBox、彼らは正しく更新するように見えます。_doctorName.stream.valueデータベースに存在する値も更新され ますが、textfieldデータは表示されません。また、色を変えてみたtextfieldので問題はなく、タイプもわかります。

アプリの小さなデモを作成しましたhttps://github.com/PritishSawant/demo/tree/master/lib

を使用する代わりにsqflite、私は使用してshared preferencesいますが、問題は解決しません


「initialValue:PatientHealthFormBloc.doctorNameValue」を削除してみて、StreamBuilderの「initialData」で開始します
Stel

@Stelありがとうございますが機能しません
ナッジ

TextEditingController(text:)

@ChinkySight TextEditingControllerを回避するためにStreamを使用しています。アプリは複雑で、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との同期が必要
ナッジ

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

さらにサポートが必要な場合はお知らせください。


動作しません...
ナッジ

ストリームで新しい名前を受け取っていますか?
Harshvardhan Joshi

はい、しかし値は更新されていません
ナッジ

で同じ新しい名前を受け取りbuilder: (context, snapshot)ますか?
Harshvardhan Joshi

テキストを入力すると、入力したテキストが表示されます。私は、DBから取得する際、初期段階では、私が手動で入力するが、それはデータベースからフェッチされるときに更新されない場合、DB value.The 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ので、そのアイデアを削りました。コントローラーを使用するだけで、ソリューションがシンプルになり、正確に機能するようになります。よくやった。
Harshvardhan Joshi

1
ありがとうございます。残念ながら、ユーザーは自分の考えに固執することに固執しており、適切な解決策を書こうとはしていなかったため、正しい応答や報奨金を原因としないことにしました。
ジョアン・ソアレス

ああ、大丈夫。じゃあ心配しないで。
Harshvardhan Joshi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.