Reputation: 341
I'm attempting to build a text field which triggers certain events which a user types in specific characters. For example, if a user types the '@' symbol, it will automatically trigger an event (in my case open an alert box). I've created a TextEditingController (_basicController) which adds a listener to the field and calls a function which looks for the last character typed into the field and detects matches to the symbol '@':
_detectLatestValue() {
var userInput = _basicController.text;
if(userInput.characters.last == "@"){
print("call to action");
_tagHandleSelect(_basicController.text);
}
}
It seems to print ("call to action") when it's supposed to, however when i call the _tagHandleSelect function (which opens a generic dialogue box), it seems to get stuck in a loop ie each time i close the alert box it opens another.
Here is the full page code:
import 'package:flutter/material.dart';
import 'package:characters/characters.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: TextEditingControllerExample(),
);
}
}
class TextEditingControllerExample extends StatefulWidget {
@override
_TextEditingControllerExampleState createState() {
return _TextEditingControllerExampleState();
}
}
class _TextEditingControllerExampleState extends State<TextEditingControllerExample> {
final _basicController = TextEditingController();
@override
void initState() {
super.initState();
_basicController.addListener(detectLatestValue);
}
@override
void dispose() {
_basicController.dispose();
super.dispose();
}
_detectLatestValue() {
var userInput = _basicController.text;
if(userInput.characters.last == "@"){
print("call to action");
_tagHandleSelect(_basicController.text);
}
}
Future<void> _tagHandleSelect(text) async {
return showDialog<void>(
context: context,
builder: (context) {
return AlertDialog(
content: Text(text),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
child: TextField(
controller: _basicController,
),
],
),
),
],
)
)
),
);
}
}```
Upvotes: 1
Views: 2734
Reputation: 1003
Adding a listener to the controller can be a little hard to manage.
If you only want to listen to changes on a specific TextField
, you can do something like this:
child: TextField(
onChanged: (value) {
if (value.endsWith("@")) {
print("call to action");
_tagHandleSelect(value);
}
},
),
This way you know onChanged
will only be triggered once.
The listener to the TextEditingController
will be triggered whenever the controller changes, which can be more than once for every text edit (for example, when the Text is focused or unfocused, it will be triggered).
I hope this can help you and you can develop your idea further!!
Upvotes: 3