9

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,
                ),
              ),
Ibrahim Ali
  • 2,083
  • 2
  • 15
  • 36

3 Answers3

8

AutoComplete has a named parameter initialValue for this.

Autocomplete<AutocompletePrediction>(  
    initialValue: const TextEditingValue(text: "Initial value"),  
    fieldViewBuilder: ...
    ...  
)  
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
log0
  • 10,489
  • 4
  • 28
  • 62
5

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

Siddharth Agrawal
  • 2,960
  • 3
  • 16
  • 37
  • 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.** – Ibrahim Ali Mar 25 '21 at 10:56
  • 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 – Siddharth Agrawal Mar 25 '21 at 11:03
  • I have commented out the `textEditingController.text = "Your initial text";` from the `Autocomplete()` . And when I call `setState()` it doesn't throw any error – Ibrahim Ali Mar 25 '21 at 11:08
  • 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 Mar 25 '21 at 11:24
  • @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 – Siddharth Agrawal Mar 25 '21 at 11:29
  • The autocomplete will not work if its `TextFormField ` isn't using its `fieldViewBuilder` controller – Ibrahim Ali Mar 25 '21 at 11:53
  • 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. – Siddharth Agrawal Mar 25 '21 at 15:30
1

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(...);
}
...
davidcv5
  • 1,027
  • 8
  • 13