Как синхронизировать Flutter TextField с полем Firestore?

Я имею task документ в Firestore, который имеет todo поле и TextField в пользовательском интерфейсе Flutter.

Пожалуйста, совет, как сделать textfield синхронизируется с todo поле, т.е.

  1. В любое время, текст в textfield изменяется при наборе пользователя, обновите todo поле с только что введенным значением.
  2. В любое время todo поле обновляется (вручную в консоли Firestore или другим пользователем), обновите textfield с самым последним значением.

Спасибо!

2 ответа

Прежде всего, поставьте TextEditingController к TextField (посмотрите на это для полного примера).

Для первой части вопроса вам нужно будет предоставить listener к TextEditingController, это listener должен вызвать функцию, например, так:

  Future<void> _updateTaskValue(String text) {
    Firestore().runTransaction((Transaction transaction) {
      Firestore.instance.document([PATH OF YOUR DOCUMENT]).updateData({"todo": text});
    });
  }

При условии, что text это контроллер text значение. Обратите внимание, что runTransaction используется, чтобы избежать параллелизма данных.

Для второй части вопроса, вам нужно будет прослушать документ. Для этого объявить в initState StreamSubscription:

subscription = Firestore.instance.document("").snapshots().listen(
    (DocumentSnapshot snapshot) => this._onDatabaseUpdate(snapshot));

Эта подписка будет запускать функцию каждый раз, когда содержимое обновляется (обновляет ли текущий пользователь TextFieldдругие пользователи обновляют его или вручную из бэк-офиса).

Вызываемая ниже функция просто обновляет контроллер text атрибут с новым содержанием:

void _onDatabaseUpdate(DocumentSnapshot snapshot) {
  setState(() {
    _controller.text = snapshot.data["todo"];
  });
}

Для полного примера, см. Эту суть.

  1. TextField onChanged обновляет значение в firebase.
  2. Прослушайте изменение значения в firebase и обновите значение для TextField с помощью TextEditingController.

Вот код:

import 'dart:async';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TODO Screen',
      theme: ThemeData(
        primarySwatch: Colors.orange,
      ),
      home: TODOScreen(),
    );
  }
}

class TODOScreen extends StatefulWidget {
  @override
  _TODOScreenState createState() => _TODOScreenState();
}

class _TODOScreenState extends State<TODOScreen> {
  final _ref = FirebaseDatabase.instance.reference().child('todo_id').child('value');
  TextEditingController _todoController = new TextEditingController();

  StreamSubscription _subscription;

  @override
  void initState() {
    super.initState();
    _subscription = _ref.onValue.listen((data) {
      String value = data.snapshot.value as String ?? "";
      updateOnChanged(value);
    });
  }

  saveOnChanged(String value) async {
    await _ref.set(value);
  }

  updateOnChanged(String value) async {
    setState(() {
      _todoController.value = _todoController.value.copyWith(
        text: value,
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TODO Screen'),
      ),
      body: Center(
        child: Container(
          padding: EdgeInsets.all(10.0),
          child: TextField(
            decoration: InputDecoration(labelText: "TODO"),
            maxLines: 5,
            onChanged: saveOnChanged,
            controller: _todoController,
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _todoController.dispose();

    if (_subscription != null) _subscription.cancel();

    super.dispose();
  }
}

Надеюсь, что это hepls!

Другие вопросы по тегам