'This expression has a type of 'void' so its value can't be used.' setState() error in Flutter

Viewed 14928

I am getting the error quoted above when I try to rebuild a class. The class I am calling, ListOfIngs(), is a class that basically creates a textField, but my goal is to create a large amount of TextFields, the variable countIngs holds the value for the exact number, in a listView. Here is the code:

        body: Container(
      padding: EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 30.0),
      child: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              Text('Ingredients',
                  style: GoogleFonts.biryani(fontSize: 15.0)),
              IconButton(
                icon: new Icon(Icons.add),
                onPressed: () {
                  setState(() {
                    countings++;
                  });
                  debugPrint('$countings');
                },
              )
            ],
          ),
          setState(() {
            ListOfIngsWidget(countings);
          }),
        ],
      ),
    )
3 Answers

Try this:

class ListOfIngs extends State<ListOfIngsWidget> {
  final int countIngs;
  final myController = new TextEditingController();
  ListOfIngs(
    this.countIngs,
  );
  Widget build(BuildContext contex) {
    return new Container(
        child: ListView.builder(
            itemCount: countIngs,
            itemBuilder: (context,index){
              return Container(
                child: TextField(
                  controller: myController,
                  decoration: InputDecoration(
                    border: OutlineInputBorder(),
                    labelText: 'Ingredient $index',
                  ),
                ),
              );
            },
          ),
       );
  }
}

A few important things first:

  • Every TextField needs its own TextEditingController, so in your case you need a list of TextEditingControllers.
  • With TextField() you create an object of type TextField. In the brackets you can't just write a for loop, because parameters to create the object are expected here.
  • Ingredient $countIngs' always gives you only the length. What you want to have is your variable i, which increases in every loop pass.
import 'package:flutter/material.dart';

class ListOfIngsWidget extends StatefulWidget {
  final int countIngs;

  const ListOfIngsWidget(this.countIngs, {Key key}) : super(key: key);

  @override
  _ListOfIngsState createState() => _ListOfIngsState();
}

class _ListOfIngsState extends State<ListOfIngsWidget> {
  List<TextEditingController> _controllerList = [];
  List<TextField> _textFieldList = [];
  
  @override
  void initState() {
    for (int i=0; i<widget.countIngs; i++) {
      TextEditingController controller = TextEditingController();
      TextField textField = TextField(
        controller: controller,
        decoration: InputDecoration(
          border: OutlineInputBorder(),
          labelText: 'Ingredient $i',
        ),
      );
      _textFieldList.add(textField);
      _controllerList.add(controller);
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
      child: Flexible(
        child: ListView(children: _textFieldList),
      ),
    );
  }
}

You can now call the widget for example with ListOfIngsWidget(5).

The problem is with the ListView. It does not have a children: [] atribute. You need to build the widget list before

List<Widget> list = [];

for(int i = 0; i < countIngs; i ++) {
  list.add(TextField(
    controller: myController,
    decoration: InputDecoration(
      border: OutlineInputBorder(),
      labelText: 'Ingredient $i',
    ),
  ));
}

Then build the ListView

...
  ListView(
    children: list
  )
...

Note: If you are building multiple TextFields, make sure you create a different controller for each of them.

You can also use ListView.builder(), which is better for many items. You can make use of functions inside of it.

Related