How to listen changes inside TextController? - flutter

I am using GetX. I need to listen changes in TextController. The follow code do not work:
class Controller extends GetxController{
final txtList = TextEditingController().obs;
#override
void onInit() {
debounce(txtList, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
}
Is does not print nothing when I am changing txtList value from UI. I suppose it's because it does not check text field inside txtList.
How to get it work?

You need to pass an RxInterface into debounce to do this via GetX. Just create an RxString and add a listener to the controller then pass the RxString into debounce.
class Controller extends GetxController {
final txtList = TextEditingController();
RxString controllerText = ''.obs;
#override
void onInit() {
txtList.addListener(() {
controllerText.value = txtList.text;
});
debounce(controllerText, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
}
Then on any page in the app you can pass in that controller into the textfield and it'll print the value after the user stops typing for 1 second.
class Home extends StatelessWidget {
final controller = Get.put(Controller());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(controller: controller.txtList), // this will print
),
);
}
}
And if you need that value for anything else it's also always accessible via controller.controllerText.value.

By TextEditingController.text, we can already get changing text input value so it does not need .obs.
To pass parameter for debounce, we should pass value itself : txtList.text. (see here: https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md)
final txtList = TextEditingController(); // 1. here
#override
void onInit() {
debounce(txtList.text, (_) { // 2. here
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
This might work.
=================== added 11/21 ==================
Here's the example. I know the RxString variable seems a duplication for TextEditingController.text, but GetX's debounce function needs RxString type variable as a parameter. I tried to find more elegant way to do this, but I couldn't find anything. Please let me know if somebody knows a better way.
// in controller
late final TextEditingController textController;
final RxString userInput = "".obs;
#override
void onInit() {
super.onInit();
textController = TextEditingController();
userInput.value = textController.text;
textController.addListener(() {
userInput.value = textController.text;
}
);
debounce(userInput, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
}

check this snippet for example to listen to TextEditingController text change listener
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(),
darkTheme: ThemeData.dark(),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController controller = TextEditingController();
#override
void initState() {
super.initState();
controller.addListener(_printLatestValue);
}
void _printLatestValue() {
print('Second text field: ${controller.text}');
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: TextField(
controller: controller,
),
);
}
}

Related

How to show a blinking cursor when textfield is enable?

I am working on the project where pressing edit button enables Textfield. Now, I want that user will now that textfield is enabled by showing a blinking cursor. Is there anyway to do that?
To focus a TextField you can give it a FocusNode and request focus on that. An example:
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
bool textFieldEnabled = false;
late FocusNode myFocusNode;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
#override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
void setTextFieldEnabled() {
setState(() {
textFieldEnabled = true;
});
WidgetsBinding.instance.addPostFrameCallback((_) {
myFocusNode.requestFocus();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(onPressed: setTextFieldEnabled, child: const Text('enable')),
TextField(enabled: textFieldEnabled, focusNode: myFocusNode)
]));
}
}
Note, at first I though you could just call myFocusNode.requestFocus(); after changing textFieldEnabled, but that didn't seem to work. Putting it in a WidgetsBinding.instance.addPostFrameCallback seemed to solve that.

Null check operator error when trying to read Passed variable in Constructor

I'm trying to read value passed from a Stateful object to another Stateful object. I've defined a simple String variable, and trying to read the value in the constructor.
It's showing error: Null check operator used on a null value.
But when I try to read the value in the widget, it works, and doesn't show any error.
Here is the main.dart
void main() {
runApp(MaterialApp(
home: HomePage(),
));
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var dummyText = "Dummy Text";
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => DPage(dummyText)));
},
child: Text('Press Me!'),
),
));
}
}
Here is the DPage where I'm trying to read variable dummyText.
class DPage extends StatefulWidget {
var dvariable;
DPage(this.dvariable);
#override
State<DPage> createState() => _DPageState();
}
class _DPageState extends State<DPage> {
_DPageState() {
print(widget.dvariable);
}
#override
Widget build(BuildContext context) {
return Container(child: Text(widget.dvariable));
}
}
if I comment the following line, which is in constructor -
print(widget.dvariable);
It runs without any problem. But if I try to access the widget.dvariable in the constructor, it throws error -
Null check operator used on a null value
How do I access this dvariable or value of "dummyText" in constructor? Any pointers will be greatly appreciated.
Note: I'm noob in dart/flutter.
You can use initState for this case. Constructor gets called before initState State and not ready to read widget class variables.
#override
void initState() {
super.initState();
print(widget.dvariable);
}
class DPage extends StatefulWidget {
var dvariable;
DPage(this.dvariable);
#override
State<DPage> createState() => _DPageState();
}
class _DPageState extends State<DPage> {
#override
void initState() {
super.initState();
print(widget.dvariable);
}
#override
Widget build(BuildContext context) {
return Container(child: Text(widget.dvariable));
}
}
Or
class DPage extends StatefulWidget {
var dvariable;
DPage(this.dvariable);
#override
State<DPage> createState() => _DPageState();
}
class _DPageState extends State<DPage> {
_DPageState() {
print(widget.dvariable);
}
#override
void initState() {
super.initState();
_DPageState();
}
#override
Widget build(BuildContext context) {
return Container(child: Text(widget.dvariable));
}
}

ObjectBox database not initializing in Flutter 2.0

I'm trying to use ObjectBox as the database in a flutter application. The following is the sample code.
However, while execution I was returned with the error of "_store is not initialized".
class _HomePageState extends State<HomePage> {
...
// 👇 ADD THIS
late Stream<List<ShopOrder>> _stream;
#override
void initState() {
super.initState();
setNewCustomer();
getApplicationDocumentsDirectory().then((dir) {
_store = Store(
getObjectBoxModel(),
directory: join(dir.path, 'objectbox'),
);
setState(() {
// 👇 ADD THIS
_stream = _store
.box<ShopOrder>()
// The simplest possible query that just gets ALL the data out of the Box
.query()
.watch(triggerImmediately: true)
// Watching the query produces a Stream<Query<ShopOrder>>
// To get the actual data inside a List<ShopOrder>, we need to call find() on the query
.map((query) => query.find());
hasBeenInitialized = true;
});
});
}
...
}```
initialize the databases in the main one and then you pass the store to the HomePage, that is why it tells you that error '_store no se inicializa'. You must declare your global store and then you pass it to each view.
late Store _stores;
void main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyState createState() => _MyState();
}
class _MyState extends State<MyApp> {
bool iniciando_store = true;
#override
void initState() {
super.initState();
initPlatformState();
getApplicationDocumentsDirectory().then((directory) {
_stores = Store(
getObjectBoxModel(),
directory: join(directory.path, 'objectbox')
);
setState(() {
iniciando_store = false;
});
});
}
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => ThemeProvider()),
],
child: Consumer<ThemeProvider>(builder: (context, theme, snapshot) {
return MaterialApp(
title: 'Object box title',
home: !iniciando_store
? MyHomePage(
title: "Home", loadingSore: iniciando_store, STORE: _stores)
: MyStatefulWidget());
}),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage(
{Key? key,
required this.title,
required this.loadingSore,
required this.STORE})
: super(key: key);
final String title;
final Store STORE;
final bool loadingSore;
#override
_MyHomePageState createState() => _MyHomePageState();
}
this is the simple way to connect with Object box

Dispose method not called in flutter

I am facing an issue in which dispose method is not called after changing screen in flutter .First of all here is the source code.
class Game extends StatefulWidget {
Game({Key key, this.title}) : super(key: key);
final String title;
#override
_GameState createState() => new _GameState();
}
class _GameState extends State<Game> with SingleTickerProviderStateMixin {
final CrosswordController myController = CrosswordController();
var chewieController = null;
var videoPlayerController = null;
Widget makeVideoStreaming(){
videoPlayerController = VideoPlayerController.network("https://somelink.com");
chewieController = ChewieController(//paramtere here
);
}
#override
void initState() {
super.initState();
this.makeVideoStreaming();
_controller = AnimationController(vsync: this, duration: Duration(minutes: gameTime));
}
#override
void dispose(){
print('DISPOSE CALLED- GAME---');
videoPlayerController.dispose();
chewieController.dispose();
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackPressed,
child: Scaffold(
key: _scaffoldKey,
drawer: NavigationDrawer(),
resizeToAvoidBottomPadding: false,
body://body here
),
);
}
}
In NavigationDrawer() i changes to some different route something like this.
onTap: () {
Navigator.pop(context); Navigator.pushNamed(context, '/edit_profile');
},
Above is just a part of code which is called after clicking on one of the item from drawer list item.
In GameState dispose method is not called why ?
Dispose method called when you remove screen from stack mean's that when you use navigator.pop() Or pushReplacement;
it's a known bug: https://github.com/flutter/flutter/issues/40940
even if you copy examples from official docs, it will not get called: https://flutter.dev/docs/cookbook/networking/web-sockets#complete-example
I've started a thread of flutter-dev to find out if something else should be used instead: https://groups.google.com/g/flutter-dev/c/-0QZFGO0p-g/m/bictyZWCCAAJ

How can I pass parameters to listeners in Flutter?

I'm new in Flutter and I am following this official example about text fields: https://flutter.dev/docs/cookbook/forms/text-field-changes
There is an axample for listen to changes in the controller of a text field widget. Please note this fragment of code _MyCustomFormState
final myController = TextEditingController();
#override
void initState() {
super.initState();
myController.addListener(_printLatestValue);
}
_printLatestValue() {
print("Second text field: ${myController.text}");
}
If I have two fields and two controllers, I would like to have just one listener, and display some message depending on which controller called the method. I would like to do something like this:
final myController1 = TextEditingController();
final myController2 = TextEditingController();
#override
void initState() {
super.initState();
myController1.addListener(_printLatestValue('message1'));
myController1.addListener(_printLatestValue('message2'));
}
_printLatestValue(message) {
print("Second text field: ${myController.text + message}");
}
which is not possible because the method addListener() uses some called VoidCallback, which have no arguments. At least that is what I understood from the Flutter docs.
So, if it is possible, how can I achieve what I'm looking for?
You're almost correct, but not quite. You're free to pass in any arguments to the listener. However, those arguments need to come from somewhere else - TextEditingController does not supply any, and it does not expect any return values. In other words, the signature should be something like: () => listener(...).
So to answer your question, you're free to do something like the following to distinguish the controllers:
void initState() {
super.initState();
firstController.addListener(() => _printLatestValue('first'));
secondController.addListener(() => _printLatestValue('second'));
}
Full working example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Text controllers',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final firstController = TextEditingController();
final secondController = TextEditingController();
void initState() {
super.initState();
firstController.addListener(() => _printLatestValue('first'));
secondController.addListener(() => _printLatestValue('second'));
}
#override
void dispose() {
firstController.dispose();
secondController.dispose();
super.dispose();
}
_printLatestValue(message) {
if (message == 'first') {
print('Received form first controller: ${firstController.text}');
} else {
print('Received from second controller: ${secondController.text}');
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Controllers', style: TextStyle(fontSize: 18)),
),
body: Center(
child: Column(
children: <Widget>[
TextField(controller: firstController,),
TextField(controller: secondController,)
],
),
),
);
}
}
Note that in this case, listener will only print the text from a TextField that was changed.