aravindd7
aravindd7

Reputation: 15

Error: Expected a value of type 'TextEditingController', but got one of type 'TextEditingValue'

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

Answers (3)

Nghien Nghien
Nghien Nghien

Reputation: 297

If you wanna use TextEditingController with ValueNotifier to handle real time when user input anything in TextField/TextFormField like picture below:

enter image description here

enter image description here

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

Peter Haddad
Peter Haddad

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

sleepingkit
sleepingkit

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

Related Questions