skip to Main Content

I fetch a list from an api, which list has some fields already defined. I want to write on some of the fields and send it back, so I use a Form and under the form I use a Consumer and a Listview.seperated to represent the list. On the fields I want to write I use a textformfield. All of these are working correctly, except one issue. When I tap outside the textformfields the ui rebuilds again and the fields take their initial values. Is it possible to prevent that ui rebuild using Selector instead of Consumer?

Form(
              key: _calendarFormKey,
              child: Consumer<CalendarViewProvider>(
                builder: (context, cal, child) {
                  if (cal.length == 0) {
                    return Center(
                      child: Text('List is empty'),
                    );
                  } else {
                    textControllers.clear();
                    int? numOfControllers = cal.length;
                    for (int i = 0; i < numOfControllers; i++) {
                      textControllers.add(TextEditingController());
                    }

                    return ListView.separated(
                        separatorBuilder: (context, index) {
                          return SizedBox(height: 10);
                        },
                        itemCount: cal.length,
                        itemBuilder: (context, index) {
                          var _cale = cal[index];

                          textControllers[index].text =
                              '${_cale.description}';

                          void clearController() {
                            context
                                .read<CalendarViewProvider>()
                                .removeCalendar(code: _cale.code);
                            textControllers[index].clear();
                          }

                          addToList(String text) {
                            caleList.clear();
                            for (int i = 0; i < numOfControllers; i++) {
                              var _cal = cal[i];
                              Map<String, dynamic> caleData = {
                                'code': _cal.code,
                                'start': _cal.start,
                                'end': _cal.end,
                                'title': _cal.title,
                                'description': textControllers[i].text,
                              };
                              caleList.add(caleData);
                            }
                          }

                          return Container(
                            height: ScreenConfig.screenHeight * .08,
                            child: Row(
                              children: [
                                SizedBox(width: 3),
                                Text(
                                  _cale.start?.substring(11, 16) ?? '',
                                  style: TextStyle(
                                      fontWeight: FontWeight.bold,
                                      color: Colors.grey[600]),
                                ),
                                Stack(
                                  children: [
                                    Image.asset(
                                      AppImages.dietDayImg,
                                      height:
                                          ScreenConfig.screenHeight * .15,
                                      width: ScreenConfig.screenWidth * .21,
                                    ),
                                    Positioned.fill(
                                      child: Center(
                                        child: Text(
                                          _cale.title?.substring(0, 1) ??
                                              '',
                                          style: TextStyle(
                                            color: Colors.white,
                                            fontWeight: FontWeight.bold,
                                            fontSize: 14,
                                          ),
                                        ),
                                      ),
                                    ),
                                  ],
                                ),
                                SizedBox(width: 1),
                                SingleChildScrollView(
                                  child: Container(
                                    height:
                                        ScreenConfig.screenHeight * .078,
                                    width: ScreenConfig.screenWidth * .55,
                                    decoration: BoxDecoration(
                                      color: Color(0xFFd6e7ea),
                                      borderRadius: BorderRadius.all(
                                        Radius.circular(10),
                                      ),
                                    ),
                                    child: Padding(
                                      padding:
                                          const EdgeInsets.only(left: 5),
                                      child: TextFormField(
                                        controller: textControllers[index],
                                        maxLines: 20,
                                        decoration: InputDecoration(
                                          border: InputBorder.none,
                                        ),
                                        onSaved: (newValue) {
                                          addToList(
                                              textControllers[index].text);
                                          textControllers[index].text =
                                              newValue!;
                                        },
                                        onChanged: (value) {
                                          caleList[index]['description'] =
                                              value;
                                          addToList(
                                              textControllers[index].text);
                                          textControllers[index].text =
                                              value;
                                        },
                                      ),
                                    ),
                                  ),
                                ),
                                IconButton(
                                  onPressed: () {
                                    deleteDialog();
                                  },
                                  icon: Icon(Icons.delete),
                                  iconSize: 12,
                                  color: Colors.red,
                                ),
                              ],
                            ),
                          );
                        });
                  }
                },
              ),
            ),

2

Answers


  1. Chosen as BEST ANSWER

    So in my existing code I deleted the declaration of the textfield controllers under the list I created. I put the results of the api inside a list, and I declare the controllers based on that list so, these textfields don't rebuild again. I put my code under the Widget build and over the return:

    var list = context.watch<CalendarViewProvider().calendarView?.results;
    list?.forEach((element) {
      element.description;
      var controller = TextEditingController(text: element.description);
      textControllers.add(controller);
    });
    

  2. Since you taged (but not mentioned) provider, I assume that you are using provider. If you are filling "cal" in the build method with something like:

    final cal = Provider.of<T>(context);
    

    It will always update. You can fill cal in initstate.
    But maybe you have also to do (here I am guessing, since I can only see your "Form-Code") or it can also work if you use "AutomaticKeepAliveClientMixin". Here for you have to make the Widget what you want to keep alife to stateful then add like that

    class _YourWidgetState extends State<YourWidget> with AutomaticKeepAliveClientMixin {
    
      @override
      Widget build(BuildContext context) {
        /// Normaly you dont need to call super in Flutter for State<T>. But since we using [AutomaticKeepAliveClientMixin],
        /// we have to call it. In Flutter is super used to call the constructor of the base Class.
        super.build(context);
    return.....;
    }
    /// this is also important
      @override
      bool get wantKeepAlive => true;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search