Home > Software engineering >  Listview.builder not updating after inserting new data
Listview.builder not updating after inserting new data

Time:03-31

I'm having troubles with my list builder. I'm trying to add more TextFormFields when the " " button next to the "Tag" text is pressed, I'm fetching the tag list from firebase and then displaying every tag from that list in a separate TextFormField, but when I try to add a new TextFormField with the " " button, nothing happens, I check if the list leght changes and indeed it changes, but nothing happens, what I would expect is to get a new TextFormField in the red square.

enter image description here

code:

import 'package:flutter/material.dart';
import '../database/firestoreHandler.dart';
import '../models/todo2.dart';
import '../widgets/dialogs.dart';

class TodoEdit extends StatefulWidget {
  String? doctitle;
  String? doctdescription;
  String? docimage;
  String? docid;
  List? doctags;

  TodoEdit({Key? key, this.doctitle, this.doctdescription, this.docimage, this.docid,this.doctags}) : super(key: key);


  @override
  _TodoEditState createState() => _TodoEditState();

}
// -----------------------------my widget------------
Widget tagForm(controller){
  return TextFormField(
    controller: controller,
    style: TextStyle(color: Colors.white),
    decoration: InputDecoration(
      labelText: "Tag",
      labelStyle: TextStyle(color: Colors.white60),
      fillColor: Colors.black,
      filled: true,
    ),
  );

}
//---------------------------------------------------
class _TodoEditState extends State<TodoEdit> {
  final _formKey = GlobalKey<FormState>();
  final tcontroller = TextEditingController();
  final dcontroller = TextEditingController();
  final icontroller = TextEditingController();
//--------------------add widget to list----------------
  void _addformWidget(list,controller) {
    setState(() {
      list.add(tagForm(controller));
    });
  }
//------------------------------------------------

  @override
  void initState() {

    super.initState();
    tcontroller.text = widget.doctitle.toString();
    dcontroller.text = widget.doctdescription.toString();
    icontroller.text = widget.docimage.toString();
    
  }

  @override
  Widget build(BuildContext context) {
//----------I add the tags to the list view for the first time-----
    var textEditingControllers = <TextEditingController>[];
    var textformFields = <Widget>[];
    widget.doctags?.forEach((element) {
      var textEditingController = new TextEditingController(text: element);
      textEditingControllers.add(textEditingController);
      //return textformFields.add(tagForm(textEditingController)
      return _addformWidget(textformFields, textEditingController);
      //);
    });
//------------------------------------------
    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        actions: [
          IconButton(onPressed: (){
            showDialog(
              barrierDismissible: false,
              context: context,
              builder: (context) {
                return AlertDialog(
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(20),
                  ),
                  title: Text('Delete TODO'),
                  actions: [
                    TextButton(
                      child: Text('Cancel'),
                      onPressed: () {
                        Navigator.pop(context);
                      },
                    ),
                    TextButton(
                      child: Text('Delete'),
                      onPressed: () {
                        deleteData(widget.docid.toString(), context);
                        setState(() {
                          showSnackBar(context, 'todo "${widget.doctitle}" successfully deleted!');
                        });
                      },
                    ),
                  ],
                );
              },
            );
          },
              icon: Icon(Icons.delete))
        ],
        backgroundColor: Colors.grey[900],
        title: Text("${widget.doctitle}"),
      ),
      body: Container(
        child: SafeArea(
        child:  Form(
          key: _formKey,
          child: Column(
            children: [
              SizedBox(height: 10),
              TextFormField(
                controller: tcontroller,
                style: TextStyle(color: Colors.white),
                decoration: InputDecoration(
                  labelText: "Title",
                  labelStyle: TextStyle(color: Colors.white60),
                  fillColor: Colors.black,
                  filled: true,
                ),
              ),
              SizedBox(height: 10),
              TextFormField(
                controller: dcontroller,
                style: TextStyle(color: Colors.white),
                decoration: InputDecoration(
                  labelText: "Description",
                  labelStyle: TextStyle(color: Colors.white60),
                  fillColor: Colors.black,
                  filled: true,
                ),
              ),
              SizedBox(height: 10),
              TextFormField(
                controller: icontroller,
                style: TextStyle(color: Colors.white),
                decoration: InputDecoration(
                  labelText: "Image url",
                  labelStyle: TextStyle(color: Colors.white60),
                  fillColor: Colors.black,
                  filled: true,
                ),
              ),
              SizedBox(height: 10),
              Row(children: [
                Text("Tags:", style:TextStyle(color: Colors.white)),
//-----------------------here I try to add the new text form field-----------
                IconButton(onPressed: (){
                  var textEditingController = new TextEditingController(text: "tag");
                  textEditingControllers.add(textEditingController);
                  _addformWidget(textformFields,textEditingController);
                  print(textformFields.length);
                },
                  icon: Icon(Icons.add,color: Colors.white,),
                )
              ],),//------------------------

              /*SingleChildScrollView(
                child: new Column(
                children: textformFields,
                )
              ),*/
//--------------------------------here I build my list--------------
              Expanded(
                  child: SizedBox(
                    height: 200.0,
                    child: ListView.builder(
                        itemCount: textformFields.length,
                        itemBuilder: (context,index) {
                          return textformFields[index];
                        }),
                  )
              ),
            ],
          ),
        ),
        ),
        ),
//--------------------------------------------------
        floatingActionButton: FloatingActionButton(
          onPressed: (){
            if(tcontroller == '' && dcontroller == '' && icontroller == ''){
              print("not valid");
            }else{
              var todo = Todo2(
                title: tcontroller.text,
                description: dcontroller.text,
                image: icontroller.text,
                //tags: tagcontroller.text,
              );
              updateData(todo, widget.docid.toString(),context);
              setState(() {
                showSnackBar(context, 'todo ${widget.doctitle} successfully updated!');
              });
            }
          },
          child: Icon(Icons.update),
    ),
    );
  }
}

Any help appreciated!

CodePudding user response:

Since you've kept the list of form fields and controllers in the build function, the widget isn't rebuilt when you call setState on them.

Instead move these to with other state variables.

  final _formKey = GlobalKey<FormState>();
  final tcontroller = TextEditingController();
  final dcontroller = TextEditingController();
  final icontroller = TextEditingController();
  
  final textEditingControllers = <TextEditingController>[];
  final textformFields = <Widget>[];

Now you can change the _addformWidget function to directly use the list without taking it as a parameter.

  void _addformWidget(TextEditingController controller) {
    setState(() {
      textformFields.add(tagForm(controller));
    });
  }

Then initialise them in the initState function.

  @override
  void initState() {

    super.initState();
    tcontroller.text = widget.doctitle.toString();
    dcontroller.text = widget.doctdescription.toString();
    icontroller.text = widget.docimage.toString();
    
    
    widget.doctags?.forEach((element) {
      final textEditingController = new TextEditingController(text: element);
      textEditingControllers.add(textEditingController);
      //return textformFields.add(tagForm(textEditingController)
      _addformWidget(textEditingController);
      //);
    });
    
  }

This ideally should fix your problem. Let me know if it doesn't and if it does, you can click the check mark to confirm that.

CodePudding user response:

//// Remove textEditingControllers and textformFields list from the build. And declare it on top.

 @override
  Widget build(BuildContext context) {
//----------I add the tags to the list view for the first time-----
    var textEditingControllers = <TextEditingController>[];
    var textformFields = <Widget>[];

//// Use like below

class _TodoEditState extends State<TodoEdit> {
  final _formKey = GlobalKey<FormState>();
  final tcontroller = TextEditingController();
  final dcontroller = TextEditingController();
  final icontroller = TextEditingController();

  var textEditingControllers = <TextEditingController>[]; //<---------
  var textformFields = <Widget>[];

////// Full Code

class TodoEdit extends StatefulWidget {
  String? doctitle;
  String? doctdescription;
  String? docimage;
  String? docid;
  List? doctags;

  TodoEdit(
      {Key? key,
        this.doctitle,
        this.doctdescription,
        this.docimage,
        this.docid,
        this.doctags})
      : super(key: key);

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

class _TodoEditState extends State<TodoEdit> {
  final _formKey = GlobalKey<FormState>();
  final tcontroller = TextEditingController();
  final dcontroller = TextEditingController();
  final icontroller = TextEditingController();

  var textEditingControllers = <TextEditingController>[];
  var textformFields = <Widget>[];

  @override
  void initState() {
    widget.doctags?.forEach((element) {
      var textEditingController = TextEditingController(text: element);
      textEditingControllers.add(textEditingController);
      //return textformFields.add(tagForm(textEditingController)
      return _addformWidget(textformFields, textEditingController);
      //);
    });
    super.initState();
    tcontroller.text = widget.doctitle.toString();
    dcontroller.text = widget.doctdescription.toString();
    icontroller.text = widget.docimage.toString();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        actions: [
          IconButton(
              onPressed: () {
                showDialog(
                  barrierDismissible: false,
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20),
                      ),
                      title: Text('Delete TODO'),
                      actions: [
                        TextButton(
                          child: Text('Cancel'),
                          onPressed: () {
                            Navigator.pop(context);
                          },
                        ),
                        TextButton(
                          child: Text('Delete'),
                          onPressed: () {
                            deleteData(widget.docid.toString(), context);
                            setState(() {
                              showSnackBar(context,
                                  'todo "${widget.doctitle}" successfully deleted!');
                            });
                          },
                        ),
                      ],
                    );
                  },
                );
              },
              icon: Icon(Icons.delete))
        ],
        backgroundColor: Colors.grey[900],
        title: Text("${widget.doctitle}"),
      ),
      body: Container(
        child: SafeArea(
          child: Form(
            key: _formKey,
            child: Column(
              children: [
                SizedBox(height: 10),
                TextFormField(
                  controller: tcontroller,
                  style: TextStyle(color: Colors.white),
                  decoration: InputDecoration(
                    labelText: "Title",
                    labelStyle: TextStyle(color: Colors.white60),
                    fillColor: Colors.black,
                    filled: true,
                  ),
                ),
                SizedBox(height: 10),
                TextFormField(
                  controller: dcontroller,
                  style: TextStyle(color: Colors.white),
                  decoration: InputDecoration(
                    labelText: "Description",
                    labelStyle: TextStyle(color: Colors.white60),
                    fillColor: Colors.black,
                    filled: true,
                  ),
                ),
                SizedBox(height: 10),
                TextFormField(
                  controller: icontroller,
                  style: TextStyle(color: Colors.white),
                  decoration: InputDecoration(
                    labelText: "Image url",
                    labelStyle: TextStyle(color: Colors.white60),
                    fillColor: Colors.black,
                    filled: true,
                  ),
                ),
                SizedBox(height: 10),
                Row(
                  children: [
                    Text("Tags:", style: TextStyle(color: Colors.white)),
//-----------------------here I try to add the new text form field-----------
                    IconButton(
                      onPressed: () {
                        var textEditingController =
                        new TextEditingController(text: "tag");
                        textEditingControllers.add(textEditingController);
                        _addformWidget(textformFields, textEditingController);
                        print(textformFields.length);
                      },
                      icon: Icon(
                        Icons.add,
                        color: Colors.white,
                      ),
                    )
                  ],
                ), //------------------------

                /*SingleChildScrollView(
                child: new Column(
                children: textformFields,
                )
              ),*/
//--------------------------------here I build my list--------------
                Expanded(
                    child: SizedBox(
                      height: 200.0,
                      child: ListView.builder(
                          itemCount: textformFields.length,
                          itemBuilder: (context, index) {
                            return textformFields[index];
                          }),
                    )),
              ],
            ),
          ),
        ),
      ),
//--------------------------------------------------
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (tcontroller == '' && dcontroller == '' && icontroller == '') {
            print("not valid");
          } else {
            var todo = Todo2(
              title: tcontroller.text,
              description: dcontroller.text,
              image: icontroller.text,
              //tags: tagcontroller.text,
            );
            updateData(todo, widget.docid.toString(), context);
            setState(() {
              showSnackBar(
                  context, 'todo ${widget.doctitle} successfully updated!');
            });
          }
        },
        child: Icon(Icons.update),
      ),
    );
  }

  //--------------------add widget to list----------------
  void _addformWidget(list, controller) {
    setState(() {
      list.add(tagForm(controller));
    });
  }

  // -----------------------------my widget------------
  Widget tagForm(controller) {
    return TextFormField(
      controller: controller,
      style: TextStyle(color: Colors.white),
      decoration: InputDecoration(
        labelText: "Tag",
        labelStyle: TextStyle(color: Colors.white60),
        fillColor: Colors.black,
        filled: true,
      ),
    );
  }
}
  • Related