Reputation: 4943
I have task
document in Firestore, which has todo
field, and TextField
in the Flutter UI.
Please advice how to make the textfield
synced with the todo
field, i.e.
textfield
is changed as user's typing, update the todo
field with the just typed value.todo
field is updated (manually in the Firestore console or by other user), update the textfield
with the most recent value.Thanks!
Upvotes: 2
Views: 5916
Reputation: 392
First of all, supply a TextEditingController
to the TextField
(take a look at this for a complete example).
For the first part of the question, you will need to provide a listener
to the TextEditingController
. This listener
should trigger a function like so :
Future<void> _updateTaskValue(String text) {
Firestore().runTransaction((Transaction transaction) {
Firestore.instance.document([PATH OF YOUR DOCUMENT]).updateData({"todo": text});
});
}
Assuming that text
is the controller's text
value. Note that runTransaction
is used to avoid data concurrency.
For the second part of the question, you will have to listen to the document. To do so, declare into initState
a StreamSubscription
:
subscription = Firestore.instance.document("").snapshots().listen(
(DocumentSnapshot snapshot) => this._onDatabaseUpdate(snapshot));
This subscription will trigger a function each time the content is updated (whether the current user updates the TextField
, another users updates it, or manually from the back office).
The function called below simply updates the controller's text
attribute with the new content :
void _onDatabaseUpdate(DocumentSnapshot snapshot) {
setState(() {
_controller.text = snapshot.data["todo"];
});
}
For a complete example, see this gist.
Upvotes: 5
Reputation: 16300
Here is the code :
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();
}
}
Hope it hepls!
Upvotes: 1