Как синхронизировать Flutter TextField с полем Firestore?
Я имею task
документ в Firestore, который имеет todo
поле и TextField
в пользовательском интерфейсе Flutter.
Пожалуйста, совет, как сделать textfield
синхронизируется с todo
поле, т.е.
- В любое время, текст в
textfield
изменяется при наборе пользователя, обновитеtodo
поле с только что введенным значением. - В любое время
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"];
});
}
Для полного примера, см. Эту суть.
- TextField onChanged обновляет значение в firebase.
- Прослушайте изменение значения в 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!