Why is my flutter TextField initialState not working - flutter

Here is the code on how i call my custom Widget called BodyInput
BodyInput(
label: 'Name',
readOnly: readOnly,
initialValue: name,
placeholder: name,
handleChange: (value) {
print(value);
},
),
both placeholder and initialState has the same value but for some reason instead of displaying the initialState my TextField is displaying the placeholder. results
and here is the BodyInput itself *for some reason it wont let me copy paste the code so here is an image instead i'm really sorry for the trouble, for some reason when i paste the code only first line is copied as code the rest is normal text

Well turnsout my widget.initialState on initState value was null :/, so i had to set the _controller value in the Widget and my code become like this
Widget build(BuildContext context) {
//Had to move this here instead of in the initState method.
_controller = new TextEditingController(text: widget.initialValue);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.label),
TextField(
onChanged: (value) {
widget.handleChange(value);
},
controller: _controller,
readOnly: widget.readOnly,
decoration: InputDecoration(
hintText: widget.placeholder, contentPadding: EdgeInsets.all(2)),
),
],
);
}
please let me know if there is a better answer

Related

What is the scope of the snapshot of a StreamBuilder widget?

I have a page with a column of TextFields. If I populate the TextFields with an existing record I do it through a TextEditingController for each field. I was passing in the QueryDocumentSnapshot from another page but I don't want to do that any longer because I am adding functionality where that no longer works. I can't use StreamProvider because I need some variables that are not available at the top of the tree in order to create the StreamProvider.
I think the best place to create the stream is in the page itself.
So now, I want to get the snapshot and initialize the TextEditingControllers in a method within the class and use them in the "build" method.
I don't know what the scope is of the snapshot that I create using StreamBuilder. How do I access the snapshot in another method in the class?
This is the column code in the build method:
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
reverse: true,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: StreamBuilder(
stream: FirestoreService().getSingleAgencyTrxns(widget.trxnId),
builder: (context, trxnSnapshot) {
if (!trxnSnapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Column(
children: <Widget>[
TextField(
autofocus: true,
keyboardType: TextInputType.text,
controller: clientFNameController,
textAlign: TextAlign.center,
onChanged: (value) {
trxnProvider.changeclientFName(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Client First Name',
labelText: 'Client First Name'),
),
SizedBox(
height: 8.0,
),
TextField(
keyboardType: TextInputType.text,
controller: clientLNameController,
textAlign: TextAlign.center,
onChanged: (value) {
trxnProvider.changeclientLName(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Client Last Name',
labelText: 'Client Last Name'),
),
SizedBox(
height: 8.0,
),
],
);
}
},
),
),
),
),
}
I initialize the TextEditingControllers through a method call in the initState method:
#override
void initState() {
getTrxn();
super.initState();
}
This is the getTrxn() method:
if (globals.currentTrxnId == null || globals.currentTrxnId == "") {
// new record: Set the textFields to blank
clientFNameController.text = "";
clientLNameController.text = "";
} else {
// Get the transaction
clientLNameController.text = someProvider?.clientLName ?? "";
clientTypeController.text = someProvider.clientType ?? "";
}
}
The snapshot variable is visible for every child widget, down from the builder property of the StreamBuilder.
This means that if you really need that info across your app you either:
Create a StreamBuilder on a top-ish level of your app;
Create several StreamBuilder across your app, which listen for the same events and behave accordingly.
The second option might be more complicated but I think that in some real-case scenarios it may be worth it: StreamBuilder re-builds its children when anything changes. Luckily, Flutter is smart enough to not re-build every element on the tree, but it still has to evaluate which Widget is marked as "dirty".

FORMS, no further idea how to implement a TextField with a CupertinoApp

This drives me nuts. I am trying to get a CupertinoTextField into a Form. But no matter what I try, everything turns out as a dead end.
The complication of my case is, the form in embedded into the Flushbar package, which provides kind of a snackbar to my CupertinoApp. And this is a stateless widget ;-(
return Flushbar(
backgroundColor: Common.inputBlue,
userInputForm : Form(
key: _formKey,
child: Column(
children: <Widget> [
_DelayStatusFormField(
initialValue: task.delayStatus,
onSaved: (value) => otherFormDataSubmit.delayStatus = value,
//onSaved: (value) => this.delayStatus = value,
),
CupertinoTextField(
controller: _delayTec,
onChanged: (text) {
state.didChange(text);
},
),
]),
),
);
In the onChanged section I intend to implement some validation, so I need kind of a rebuild. But setState obviously doesn't work without a proper state.
Using TextFormField also looks kind of dodgy, because I do not only have to embed this in Material( but in loads of further localization Widgets.
The most desirable solution, is this one where I tried several variants: embed the CupertinoTextField in a FormField class
class _DelayFormField extends FormField<String> {
_DelayFormField({
FormFieldSetter<String> onSaved,
String initialValue,
bool enabled,
GlobalKey key,
}) : super(
onSaved: onSaved,
initialValue: initialValue,
key: key,
builder: (FormFieldState<String> state) {
//TextEditingController inputTec = TextEditingController(text: initialValue);
return Column(children: [
SizedBox(
width: 100, height: 30,
child: CupertinoTextField(
//controller: inputTec,
enabled: true,
onChanged: (text) {
initialValue = text;
state.didChange(text);
},
)),
]);
}
);
}
The problem here, I the TextEditingController is reinitialized on any rebuild with initialVale, loosing my input. I have got around this by assigning the input to initialVale, but the cursor is then always set leading to the prefilled digits. So you type the number backwards. Since everything is in the class' initialization, I cannot find a spot where to initialize the TextEditingController outside of the build method.
Any other idea on how to solve this? Getting such a class working would be great, since one could then simply re-use this class, frequently.

How to call a method once when text editing is completed fully in flutter TextFormField?

In Flutter TextFormField, I want to call a method once editing is completed fully,I don't want to call the method while the user is changing the text in text form field(By using listener or by onchanged function), By using OnEditingComplete Function I can achieve this requirement, but the issue is oneditingcomplete is called only when the done button in the keyboard is tapped, when changing the focus after editing from one text field to another textfield onEditingComplete function is not working, So what is the best way to detect once editing is complete fully by the user.
`TextField(
onEditingComplete: () {//this is called only when done or ok is button is tapped in keyboard
print('test');
},
Using the FocusScopeWidget helps me resolve this issue https://api.flutter.dev/flutter/widgets/FocusNode-class.html,
When user press done button in the keyboard onsubmitted function is called and when user change focus focus scope widget is used.
FocusScope(
onFocusChange: (value) {
if (!value) {
//here checkAndUpdate();
}
},
child: TextFormField(
key: Key('productSet${DateTime.now().toIso8601String()}'),
getImmediateSuggestions: true,
textFieldConfiguration: TextFieldConfiguration(
onSubmitted: (cal) {
//here checkAndUpdate();
},
Use TextFormField and some sort of trigger like button pressed.
Use Global key to keep state of form, when save the form
...
class _Form extends State<Initialize> {
final _formKey = GlobalKey<FormState>();//create global key with FormState type
String _variableValue; //to hold data after save the form
#override
Widget build(BuildContext context) {
return form(
key: _formkey,
child: Column(
children: [
TextFormField(
onSaved: (value) {
_variableValue= value;
}
),
OutlineButton.icon(
onPressed: () {
_formKey.currentState.save();//should call this method to save value on _variableValue
},
icon: Icon(Icons.plus)
),
],
),
),
}
}
good luck
You can use TextFormField instead of TextField:
TextFormField(
decoration: InputDecoration(labelText: 'First Name'),
onSaved: (val) => setState(() => _firstName = val),
)
Realistic Forms in Flutter

Flutter using EditableText

I'm trying to figure out how to use the TextEditor in Flutter.
I have "Card Editor" (basically I want to be able to work on the equivalent of a paragraph of text)
new EditableText(
autofocus: true,
maxLines: null,
backgroundCursorColor: Colors.amber,
cursorColor: Colors.green,
style: TextStyle(),
focusNode: FocusNode(),
controller: controller,
onSubmitted: (val) {
_addCard(val);
Navigator.pop(context);
},
)
I adapted this from an example of a TextField.
But I have a couple of questions.
Firstly, it doesn't seem to show anything when I type. The cursor moves, but no text is visible. Is that the default when there's no explicit style?
Secondly, how do I trigger the submit? With a TextField, the CR / Enter button does this. Obviously I see why you don't necessarily want that with EditableText But what should I do instead?
Third, I need to be able to put default text into this widget. I tried adding a "value" attribute to the EditableText, but that doesn't seem to be right. What's the way to do this?
from TextField class - material library - Dart API :
EditableText, which is the raw text editing control at the heart of a TextField. The EditableText widget is rarely used directly unless you are implementing an entirely different design language, such as Cupertino.
here an example of TextField , from my app flutter listview CRUD app using nonsecure rest api
class _TaskEditPageWidgetState extends State<TaskEditPageWidget> {
TextEditingController _noteController;
#override
void initState() {
super.initState();
_noteController = TextEditingController.fromValue(
TextEditingValue(
text: widget.taskOpj.note,
),
);
}
#override
void dispose() {
_noteController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar(),
body: _body(),
);
}
Widget _appBar() {
return AppBar(
title: new Text("Edit Task"),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.save),
onPressed: _save,
),
],
);
}
Widget _body() {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Text("Note:"),
TextField(
decoration: InputDecoration(border: InputBorder.none),
autofocus: true,
keyboardType: TextInputType.multiline,
maxLines: null,
controller: _noteController),
],
),
);
}
Future _save() async {
widget.taskOpj.note = _noteController.text;
await Tasks.updateTask(widget.taskOpj);
widget.notifyParent();
Navigator.pop(context);
}
}
Just add this line:
style: TextStyle(
decorationThickness: 0.001,
),

Changing focus from one text field to the next in Flutter

I have two textFormField widgets. Once the user has completed the first text field I would like to focus on the next textField. Is there a way to do this in Flutter? Currently, the done button just closes the keyboard. I was guessing the focusNode class might be the answer to this but not really sure how that works does anyone have any good examples of focusNode class? Thanks in advance.
Yes, FocusNode and the onFieldSubmitted from a TextFormField are probably the way to go.
FocusScope.of(context).requestFocus(focusNode);
Here is an example that may help:
FocusNode textSecondFocusNode = new FocusNode();
TextFormField textFirst = new TextFormField(
onFieldSubmitted: (String value) {
FocusScope.of(context).requestFocus(textSecondFocusNode);
},
);
TextFormField textSecond = new TextFormField(
focusNode: textSecondFocusNode,
);
// render textFirst and textSecond where you want
You may also want to trigger FocusScope.of() from a button rather than onFieldSubmitted, but hopefully the above example gives you enough context to construct an appropriate solution for your use case.
Screenshot:
No need to use FocusNode
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
TextField(
decoration: InputDecoration(hintText: 'First Name'),
textInputAction: TextInputAction.next,
onEditingComplete: () => FocusScope.of(context).nextFocus(),
),
TextField(
decoration: InputDecoration(hintText: 'Last Name'),
textInputAction: TextInputAction.done,
onSubmitted: (_) => FocusScope.of(context).unfocus(),
),
],
),
);
}
There's a similar method like in Android.
Add
textInputAction
parameter to the TextFormField Widget, then add the property as;
TextInputAction.next
This is how I did it:
var _focusNodes = List.generate(6, (index) => FocusNode()));
And in the TextFormField:
TextFormField(
focusNode: _focusNodes[i],
maxLines: 1,
textInputAction: TextInputAction.next,
onChanged: (text) {
if (i < _controllers.length) {
if (text.isEmpty)
_focusNodes[i - 1].requestFocus();
else
_focusNodes[i + 1].requestFocus();
}
},
),