0

I´m trying something like that. Load the service in Future Builder, set Text Field values and then write the component.

 final data = FutureBuilder(
            future: DatameterService.getMapData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                setState(() {
                  calleController.text = snapshot.data.calle;
                  paisController.text = snapshot.data.pais;
                  provinciaController.text = snapshot.data.provincia;
                  poblacionController.text = snapshot.data.poblacion;
                  postalController.text = snapshot.data.postal;
                });
                return form;
              } else {
                return indicator;
              }

But return

setState() or markNeedsBuild() called during build.

So the question is: How can fill TextField inputs values using FutureBuilder?

El Hombre Sin Nombre
  • 2,906
  • 18
  • 49
  • 92

2 Answers2

6

You should never call setState in build, and the reason is simple: setState causes a build, and build calls setState - you're in an infinite loop. That's why the engine tells you explicitly that you shouldn't try to do this.

In fact, you should not be doing any business logic inside build. From your code, it looks like you wanna load some data when the page appears and set some initial fields to your TextFields. I don't think you want to be using a FutureBuilder here, since you have a StatefulWidget. Instead, you can move the future out of the build and have it be called in initState.

Something like this:

class _MyState extends State<MyWidget> {
  Map<String, dynamic> _data;
  bool _loading;
  TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    // start fetching
    _loading = true;
    _data = {};
    _controller = TextEditingController();
    getData().then((data) {
      setState(() {
        _data = data;
        _loading = false;
        _controller.text = _data['text'];
      });
    });
  }

  Widget build(BuildContext context) {
    // handle loading vs. not loading
    if (_loading) return CircularProgressIndicator();
    return Container(
      // the rest of your code
    );
  }
}

You don't really even need to store _data but it could be useful for resetting the forms or something.

David L.
  • 762
  • 4
  • 7
  • The approach I have been looking for since FutureBuilder and StreamBuilder were not suitable for me – Geek Guy May 20 '20 at 21:14
1

Basically you need to understand what a FutureBuilder to call that way. A FutureBuilder has a child future: to which you assign an asynchronous method which has .then attached to it. '.then' will be called once the asynchronous process completes.

Coming to the answer, you can call setState this way.

myFutureMethod.then((value) => {
      setState(() {
        value = true;
      })
    });
madhu131313
  • 7,003
  • 7
  • 40
  • 53