Search code examples
fluttertexteditingcontroller

How do i store the previous state and didn't lose the TextEditingController data while state changes


Here i created the some textfield and the dropdownlist when the dropdwonlist value select then i have to run setstate to update the dropdownlist value, after selecting new dropdown value the value of textfield is gone i have idea why this is happening bcoz whenever the setstate called the whole widget will rebuild so it also reset the controllers. so what is the solution about this? here is code .

import 'package:attend/constants.dart/enums.dart';
import 'package:attend/providers/user_data_provider.dart';
import 'package:attend/screens/faculty_screens/faculty_home_screen.dart';
import 'package:attend/screens/student_screens/screens/student_screen.dart';
import 'package:attend/widgets.dart/profile_image.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/cupertino.dart';

class ProfileDetailScreen extends StatefulWidget {
  static const routeName = '/profile-detail-screen';
  const ProfileDetailScreen({super.key});

  @override
  State<ProfileDetailScreen> createState() => _ProfileDetailScreenState();
}

class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
  final _formKey = GlobalKey<FormState>();

  var selectedGender = 'Male';
  final _nameCon = TextEditingController();
  final _surnameCon = TextEditingController();
  final _enrollmentCon = TextEditingController();
  var isValid = false;


  @override
  void dispose() {
    _nameCon.dispose();
    _surnameCon.dispose();
    _enrollmentCon.dispose();
    super.dispose();
  }

  void saveData() async {
    isValid = _formKey.currentState!.validate();

    if (!isValid) {
      return;
    }

    var gender = Genders.Other;
    if (selectedGender == Genders.Male.name) {
      gender = Genders.Male;
    } else if (selectedGender == Genders.Female.name) {
      gender = Genders.Female;
    }
  }

  @override
  Widget build(BuildContext context) {
    final userData = Provider.of<UserDataProvider>(context, listen: false);

    //! set controller data if edit the profile
    _nameCon.text = userData.name ?? '';
    _surnameCon.text = userData.surname ?? '';

    return Scaffold(
      appBar: AppBar(
        title: Text('Profile details'),
        actions: [
          IconButton(
              onPressed: () {
                saveData();
              },
              icon: Icon(
                Icons.save,
              ))
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              ProfileImage(selectedGender: selectedGender),
              SizedBox(height: 20),

              //! name textfield
              TextFormField(
                textCapitalization: TextCapitalization.sentences,
                decoration: InputDecoration(
                  contentPadding:
                      EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                  focusedBorder: OutlineInputBorder(
                    borderSide: BorderSide(color: Colors.grey),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  errorBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: BorderSide(
                      color: Colors.red,
                    ),
                  ),
                  enabledBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: BorderSide(
                      color: Colors.grey,
                    ),
                  ),
                  filled: true,
                  fillColor: Colors.grey.shade100,
                  labelText: 'Enter your name',
                  labelStyle: TextStyle(color: Colors.black, fontSize: 15),
                ),
                validator: (value) {
                  if (value!.isEmpty) {
                    return 'Please enter name!';
                  } else if (value.length <= 2) {
                    return 'Name at least 3 character long!';
                  }
                  return null;
                },
                controller: _nameCon,
                textInputAction: TextInputAction.next,
              ),
              SizedBox(height: 20),

              //! surname textfield
              TextFormField(
                textCapitalization: TextCapitalization.sentences,
                decoration: InputDecoration(
                  contentPadding:
                      EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                  focusedBorder: OutlineInputBorder(
                    borderSide: BorderSide(color: Colors.grey),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  errorBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: BorderSide(
                      color: Colors.red,
                    ),
                  ),
                  enabledBorder: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15),
                    borderSide: BorderSide(
                      color: Colors.grey,
                    ),
                  ),
                  filled: true,
                  fillColor: Colors.grey.shade100,
                  labelText: 'Enter your surname',
                  labelStyle: TextStyle(color: Colors.black, fontSize: 15),
                ),
                validator: (value) {
                  if (value!.isEmpty) {
                    return 'Please enter surname!';
                  } else if (value.length <= 2) {
                    return 'Surname at least 3 character long!';
                  }
                  return null;
                },
                controller: _surnameCon,
                textInputAction: userData.role == Roles.student
                    ? TextInputAction.next
                    : TextInputAction.done,
              ),
              SizedBox(height: 20),

              //! if student then he has to add enrollment no
              if (userData.role == Roles.student)
                TextFormField(
                  textCapitalization: TextCapitalization.sentences,
                  decoration: InputDecoration(
                    contentPadding:
                        EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                    focusedBorder: OutlineInputBorder(
                      borderSide: BorderSide(color: Colors.grey),
                      borderRadius: BorderRadius.circular(15),
                    ),
                    errorBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(15),
                      borderSide: BorderSide(
                        color: Colors.red,
                      ),
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(15),
                      borderSide: BorderSide(
                        color: Colors.grey,
                      ),
                    ),
                    filled: true,
                    fillColor: Colors.grey.shade100,
                    labelText: 'Enter your enrollment no',
                    labelStyle: TextStyle(color: Colors.black, fontSize: 15),
                  ),
                  validator: (value) {
                    if (value!.isEmpty) {
                      return 'Please enter enrollment no!';
                    } else if (value.length <= 2) {
                      return 'Please enter valid enrollment no!';
                    }
                    return null;
                  },
                  controller: _enrollmentCon,
                  textInputAction: userData.role == Roles.student
                      ? TextInputAction.done
                      : TextInputAction.next,
                ),
              SizedBox(height: 20),

              //! selected gender
              Row(
                children: [
                  Text(
                    'Gender ',
                    style: TextStyle(fontSize: 17),
                  ),
                  SizedBox(
                    width: 40,
                  ),
                  DropdownButton<String>(
                    dropdownColor: Colors.purple.shade50,
                    value: selectedGender,
                    onChanged: (newValue) {
                      setState(() {
                        selectedGender = newValue!;
                      });
                    },
                    items: <String>['Male', 'Female', 'Others']
                        .map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(
                          value,
                          style: TextStyle(
                              fontWeight: FontWeight.normal, fontSize: 15),
                        ),
                      );
                    }).toList(),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Solution

  • I noticed that every time the _ProfileDetailScreenState rebuilt, _nameCon and _surnameCon text were reset

      @override
      Widget build(BuildContext context) {
        final userData = Provider.of<UserDataProvider>(context, listen: false);
    
        //! set controller data if edit the profile
        _nameCon.text = userData.name ?? '';
        _surnameCon.text = userData.surname ?? '';
    ...
    }
    

    so you may need move these code into initState or didChangeDependencies like below

      @override
      void initState() {
        super.initState();
        final userData = Provider.of<UserDataProvider>(context, listen: false);
    
        //! set controller data if edit the profile
        _nameCon.text = userData.name ?? '';
        _surnameCon.text = userData.surname ?? '';
      }
    

    or

      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        final userData = Provider.of<UserDataProvider>(context, listen: false);
    
        //! set controller data if edit the profile
        _nameCon.text = userData.name ?? '';
        _surnameCon.text = userData.surname ?? '';
      }