Reputation: 15
I'm trying to wrap a ValueListenableBuilder around a Textfield which has a functionality of taking input text and returning the same text. The original purpose is to persist the input data through a database. But while implementing the basic code given below, I'm getting the error "Expected a value of type 'TextEditingController', but got one of type 'TextEditingValue'". Could you please enlighten me on the error?
import 'package:flutter/material.dart';
void main() => runApp(MyTextFieldApp());
class MyTextFieldApp extends StatelessWidget {
final _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.white,
body: Container(
padding: EdgeInsets.all(24.0),
child: Center(
child: ValueListenableBuilder(
valueListenable: _controller,
builder: (BuildContext context, _controller, _ ) {
return TextField(
autofocus: true,
maxLines: 6,
controller: _controller,
decoration: InputDecoration(
labelText: "Note",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
);
},
),
)
)
)
);
}
}
Upvotes: 0
Views: 2992
Reputation: 297
If you wanna use TextEditingController
with ValueNotifier
to handle real time when user input anything in TextField/TextFormField
like picture below:
Ex: For my prj, I'm handling to display or not the Text('This email not match format ...') below the Email TextField when the user input from keyboard.
If matched with the email format: hide the Text (red Color).
If not match: show the Text (red Color).
So, in order to handle realtime, you can wrap your TextFormField (with TextEditingController related) by ValueListenableBuilder with valueListenable
is editingController
corresponding.
CustomTextField(
hintText: R.strings.emailHint!,
labelTextField: "Email",
isRequired: true,
textController: editEmailController, // use editEmailController for TextField related.
focusNode: editEmailFocusNode,
textInputType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
),
ValueListenableBuilder(
valueListenable: editEmailController, // no need to define the variable of ValueNotifier, use directly the textEditingController variable of TextFormField related.
builder: (_, value, __) {
return editEmailController.text.trim().isNotEmpty &&
validateEmail(editEmailController.text.trim()) ==
false
? Align(
alignment: Alignment.centerLeft,
child: Text(
R.strings.emailNotMatchFormat!,
style: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 12,
color: Colors.redAccent,
),
),
)
: const SizedBox();
},
),
Upvotes: 0
Reputation: 80914
You should do the following:
import 'package:flutter/material.dart';
void main() => runApp(MyTextFieldApp());
class MyTextFieldApp extends StatelessWidget {
final _controller = TextEditingController();
final ValueNotifier valueNotifier = ValueNotifier("initial");
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar( title : Text("Title")),
backgroundColor: Colors.white,
body: Container(
padding: EdgeInsets.all(24.0),
child: Center(
child: ValueListenableBuilder(
valueListenable: valueNotifier,
builder: (BuildContext context, values, child ) {
return Column(
children : <Widget>[
TextField(
autofocus: true,
maxLines: 6,
controller: _controller,
decoration: InputDecoration(
labelText: "Note",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
),
RaisedButton(child : Text("click me"),onPressed : (){
valueNotifier.value = _controller.text;
}),
Text(values),
],
);
},
),
)
)
)
);
}
}
From the docs:
ValueListenableBuilder<T>
A widget whose content stays synced with a ValueListenable.
Given a ValueListenable and a builder which builds widgets from concrete values of T, this class will automatically register itself as a listener of the ValueListenable and call the builder with updated values when the value changes.
The valueListenable
property is of type ValueListenable<T>
, which is an interface implemented by ValueNotifier<T>
.
Therefore you need to create an instance of ValueNotifier<T>
:
final ValueNotifier valueNotifier = ValueNotifier("initial");
In this case, I created it with type String
with an intial value initial
. Then assign this instance to the property valueListenable
:
valueListenable: valueNotifier,
The builder
which is of type ValueWidgetBuilder<T>
will only get called when valueNotifier
is updated.
Therefore you can create a RaisedButton
and onPressed
, you can update the valueNotifier
value, which will call the builder
and update the Text
widget.
https://api.flutter.dev/flutter/widgets/ValueListenableBuilder-class.html
Upvotes: 1
Reputation: 628
You are not pass a TextEditingController to the TextField
ValueListenableBuilder(
valueListenable: _controller,
builder: (BuildContext context, _controller, _ ) {
// this _controller is not equal to the valueListenable: _controller above, it means _controller.value
return TextField(
autofocus: true,
maxLines: 6,
controller: _controller,
decoration: InputDecoration(
labelText: "Note",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
);
},
),
ValueListenableBuilder(
valueListenable: _controller,
builder: (BuildContext context, _value, _ ) {
return TextField(
autofocus: true,
maxLines: 6,
controller: _controller,// assign the TextEditingController
decoration: InputDecoration(
labelText: "Note",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
);
},
),
Upvotes: 1