Flutter 2 - Set initial value of an Autocomplete TextFormField

3,477

Solution 1

EDIT

I just realized you are using TextFormField which has a parameter called initialValue. IF you do not need the textediting controller, this answer should work

fieldViewBuilder: (context, textEditingController,
                        focusNode, onFieldSubmitted) =>
                    TextFormField(                             
             
                   focusNode: focusNode,
                   initialValue:"Your initial Value",
                ),

or if you are using your controller try

fieldViewBuilder: (context, textEditingController,
                        focusNode, onFieldSubmitted) =>
                    TextFormField(                             
                  controller: textEditingController..text="Initial Value",
                   focusNode: focusNode,
                ),

ORIGINAL ANSWER

Why don't you use that text editing controller itself. The code will be something like this

Autocomplete(
                optionsBuilder: (TextEditingValue textEditingValue) {
                  if (textEditingValue.text == '') return [];

                  return this
                      .productNames
                      .where((Map<String, dynamic> option) {
                    return option['ar']
                        .toLowerCase()
                        .contains(textEditingValue.text.toLowerCase());
                  });
                },
                fieldViewBuilder: (context, textEditingController,
                        focusNode, onFieldSubmitted){
                    textEditingController.text  = "Your initial text";// You can use the next snip of code if you dont want the initial text to come when you use setState((){});  
                    return TextFormField(                             
                  controller: textEditingController,//uses fieldViewBuilder TextEditingController
                   focusNode: focusNode,
                ),
               }
              ),

If you are using setState and the above piece of code keeps replacing the text with the initial text, do something like

Autocomplete(
                optionsBuilder: (TextEditingValue textEditingValue) {
                  if (textEditingValue.text == '') return [];

                  return this
                      .productNames
                      .where((Map<String, dynamic> option) {
                    return option['ar']
                        .toLowerCase()
                        .contains(textEditingValue.text.toLowerCase());
                  });
                },
                fieldViewBuilder: (context, textEditingController,
                        focusNode, onFieldSubmitted){
                    textEditingController.text = textEditingController.text  == ""? "Inital Text":textEditingController.text;// You can use the next snip of code if you dont want the initial text to come when you use setState((){});  
                    return TextFormField(                             
                  controller: textEditingController,//uses fieldViewBuilder TextEditingController
                   focusNode: focusNode,
                ),
               }
              ),

The last solution is not too elegant but works. I will let you know if I find a better solution. You can even assign this textEditingController to a global variable declared at the top and access it from anywhere in the code. And instead of checking if the text is empty, increase the value of a new variable everytime you setState and if the value is == 0, you can set initial text

Solution 2

AutoComplete has a named parameter initialValue for this.

Autocomplete<AutocompletePrediction>(  
    initialValue: const TextEditingValue(text: "Initial value"),  
    fieldViewBuilder: ...
    ...  
)  

Solution 3

This is the solution I found for TextFormField. Making sure the controller is updated at the end of the frame.

fieldViewBuilder: (BuildContext context,
  TextEditingController fieldTextEditingController,
  FocusNode fieldFocusNode,
  VoidCallback onFieldSubmitted) {

  SchedulerBinding.instance?.addPostFrameCallback((_) { // <--- this part
    var initialValue = someValueThatGotUpdatedDuringBuild;

    fieldTextEditingController.text = initialValue;
  });
  return TextFormField(...);
}
...
Share:
3,477
ibrahimxcool
Author by

ibrahimxcool

🧠 - Don't practice what you don't want to become. 🥶 - Learning Angular &amp; Flutter

Updated on November 26, 2022

Comments

  • ibrahimxcool
    ibrahimxcool over 1 year

    I can't use TextEditingController because the TextFormField uses the Autocomplete fieldViewBuilder TextEditingController

    Autocomplete(
                    optionsBuilder: (TextEditingValue textEditingValue) {
                      if (textEditingValue.text == '') return [];
    
                      return this
                          .productNames
                          .where((Map<String, dynamic> option) {
                        return option['ar']
                            .toLowerCase()
                            .contains(textEditingValue.text.toLowerCase());
                      });
                    },
                    fieldViewBuilder: (context, textEditingController,
                            focusNode, onFieldSubmitted) =>
                        TextFormField(                             
                      controller: textEditingController,//uses fieldViewBuilder TextEditingController
                       focusNode: focusNode,
                    ),
                  ),
    
  • ibrahimxcool
    ibrahimxcool about 3 years
    This is what I'm currently using.. But every time I change the initial value and call setState() . I get the following error.. It does work but because of this error i assume its not the right way. The following assertion was thrown while dispatching notifications for TextEditingController: setState() or markNeedsBuild() called during build.
  • Siddharth Agrawal
    Siddharth Agrawal about 3 years
    I am not exactly sure why this error is being thrown specific to your project, I will have to view the code files but the reason this is called is because you are calling the setState() method too early without the build being completed. The error does not matter as the build is completed instantly so the change can be run
  • ibrahimxcool
    ibrahimxcool about 3 years
    I have commented out the textEditingController.text = "Your initial text"; from the Autocomplete() . And when I call setState() it doesn't throw any error
  • Siddharth Agrawal
    Siddharth Agrawal about 3 years
    I guess changing the text will rebuild the text field which will make an infinite loop. Try setting a counter variable in the top and set it to 0. Then in the builder, check if the counter variable is 0. If it is 0, set the initial text(It might rebuild it but only once) and add one to the counter variable. Maybe assign the initial text in a delayed async function
  • Siddharth Agrawal
    Siddharth Agrawal about 3 years
    @ibrahimxcool I have just added 2 new ways. Try the first one if you do not need the controller and try the second one if u need the controller
  • ibrahimxcool
    ibrahimxcool about 3 years
    The autocomplete will not work if its TextFormField isn't using its fieldViewBuilder controller
  • Siddharth Agrawal
    Siddharth Agrawal about 3 years
    The second option uses the controller provided by the fieldViewBuilder and edits its text. You can use the counter variable solution I suggested before to solve the problem if the initial text keeps rebuilding.
  • davidcv5
    davidcv5 about 3 years
    @thenoobslayer, see above, might solve your issue, if you're still having it.
  • user3056783
    user3056783 almost 3 years
    This worked for me but in newer version of Flutter it should be ` WidgetsBinding.instance.addPostFrameCallback((_) { `