Làm cách nào để cập nhật giá trị cho TextField bằng StreamBuilder?


13

Tôi có một textfieldvà tôi đang sử dụng sqflitecơ sở dữ liệu trong ứng dụng của tôi. Các sqflitecó một giá trị mà tôi cần để gán cho tôitextfield

Đây là textfieldmã của tôi

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

Bây giờ trong initstatephương thức của lớp tôi, tôi đang tìm nạp giá trị từ cơ sở dữ liệu. Đây là một hoạt động không đồng bộ nên cần có thời gian.

Lớp học của tôi có một mã như sau

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

vì vậy ngay sau khi tôi nhận được giá trị từ cơ sở dữ liệu, tôi gọi sau

doctorNameChanged("valuefromdatabase");

nhưng tôi không thể thấy giá trị trong trường văn bản của tôi. Ngoài ra có một giá trị hiện diện trong cơ sở dữ liệu của tôi. Có thể cập nhật giá trị mà không cần sử dụng TextEditingControllerhoặc setState. Tôi ma cố gắng để tránh những người như lớp học của tôi được chia thành nhiều chuncks và cách quá phức tạp để sử dụng bất kỳ trên, chúng tôi đã cố gắng sử dụng phương pháp tương tự với RadioButtonCheckBoxvà họ dường như cập nhật đúng. Giá trị cũng được cập nhật trong _doctorName.stream.valueđó có trong cơ sở dữ liệu nhưng textfieldkhông hiển thị bất kỳ dữ liệu nào. Ngoài ra tôi đã thử thay đổi màu sắc textfieldvì vậy không có vấn đề gì cũng như tôi có thể thấy những gì tôi gõ.

Tôi đã tạo một bản demo nhỏ của ứng dụng https://github.com/PritishSawant/demo/tree/master/lib

Thay vì sử dụng sqflite, tôi đang sử dụng shared preferencesnhưng vấn đề vẫn tồn tại


Hãy thử xóa "initValue: BNHealthFormBloc.doctorNameValue" và khởi động nó trong "initData" từ StreamBuilder
Stel

@Stel Cảm ơn nhưng không hoạt động
Nudge

Bạn có thể sử dụng TextEditingCont kiểm soát (văn bản :)

@ChinkySight Tôi đang sử dụng Stream để tránh TextEditingControll. Ứng dụng này rất phức tạp và việc sử dụng TextEditingCont kiểm soát là không khả thi
Nudge

Trong ví dụ của bạn, bạn hoàn toàn không sử dụng ảnh chụp nhanh. Dữ liệu nào bạn muốn trích xuất từ ​​nó để sử dụng trong TextFormField của bạn? Tại sao bạn không thể sử dụng TextEditingControll?
João Soares

Câu trả lời:


4

OK để cuối cùng tôi tìm thấy giải pháp cho vấn đề của tôi.

Sau đây là mã của tôi, tôi vừa sử dụng SharedPreferencesthay vì ví sqflitedụ bên dưới. Điều này có thể được thực hiện vớisqflite

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

Đây là một giải pháp cực kỳ thiết kế. Tôi ước bạn đã giải thích chính xác những gì bạn muốn đạt được ban đầu thay vì muốn chúng tôi sửa giải pháp cụ thể của bạn. Như tôi đã nhận xét về câu hỏi của bạn, bạn dường như muốn thực hiện cập nhật theo thời gian thực cho TextField có thể đang được người dùng sử dụng tích cực. Điều này là rất lạ và có khả năng xấu UX.
João Soares

@ JoãoSoares Bạn có thể gửi giải pháp của bạn. Tôi rất vui khi được thưởng tiền thưởng và chấp nhận giải pháp của bạn nếu nó tốt hơn của tôi. Tôi vừa đăng một giải pháp dễ dàng hơn để mọi người có thể hiểu nhưng trong thực tế, ứng dụng của tôi yêu cầu đồng bộ hóa với sqflite cũng như Firestore để nó có thể được xem xét kỹ hơn cho bạn
Nudge

Nếu bạn có thể giải thích lý do tại sao bạn muốn Truyền phát (cập nhật) giá trị của TextFieldForm cùng lúc người dùng có thể đang sử dụng nó, tôi có thể giúp bạn. Đồng bộ hóa với SQFlite và Firestore không liên quan đến tuyên bố của tôi rằng giải pháp bạn đưa ra là quá kỹ thuật.
João Soares

@ JoãoSoares Vui lòng đọc lại câu hỏi.
Nudge

Tôi đã đọc câu hỏi nhiều lần rồi và đã thấy mã bạn chia sẻ trên GitHub. Giải thích của bạn nói về những gì bạn muốn làm và cách bạn muốn viết mã. Nó không giải thích lý do tại sao bạn muốn có một TextFormField được điền theo cách đó với Truyền dữ liệu hoặc tiền đề cho hành vi đó.
João Soares

2

Hãy thử cách tiếp cận sau:

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

Hãy cho tôi biết nếu bạn cần thêm trợ giúp.


không hoạt động ...
Nudge

bạn có nhận được tên mới trong luồng không?
Harshvardhan Joshi

có nhưng giá trị không được cập nhật
Nudge

Bạn có nhận được cùng tên mới trong builder: (context, snapshot)?
Harshvardhan Joshi

Khi tôi gõ một văn bản, tôi nhận được văn bản đánh máy. Ở giai đoạn ban đầu khi tôi tìm nạp từ db thì nó đang in giá trị db. StreamBuilder hoạt động tốt và cập nhật giá trị khi tôi nhập thủ công nhưng nó không cập nhật khi được tìm nạp từ cơ sở dữ liệu
Nudge

1

Những gì được đề xuất trong ý kiến ​​của tôi là một cái gì đó như thế này:

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

Tôi không muốn viết câu trả lời này mà không hiểu lý do tại sao bạn không muốn sử dụng TextEditingControll hoặc setState. Nhưng điều này sẽ đạt được những gì bạn muốn trong khi sử dụng mẫu Bloc.


Tôi đã có suy nghĩ này ngay từ đầu, nhưng vì câu hỏi được trích dẫn và @Nudge đã khăng khăng không sử dụng TextEditController, vì vậy tôi đã loại bỏ Ý tưởng đó. Thật tuyệt khi chỉ bằng cách sử dụng bộ điều khiển, giải pháp trở nên đơn giản và nhỏ để hoạt động chính xác. Bạn đã làm rất tốt.
Harshvardhan Joshi

1
Cảm ơn bạn tôi đánh giá cao nó. Thật không may, người dùng dường như kiên quyết bám vào ý tưởng của mình và không cố gắng viết một giải pháp thích hợp, vì vậy họ quyết định không quy kết phản hồi chính xác hoặc tiền thưởng.
João Soares

Ờ được rồi. Đừng bận tâm.
Harshvardhan Joshi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.