1

I have a class named User which basically has two variables. name and age. Also, I have another class named UserList.The aim of this class is to add the user objects to a list and return that list.

User model

class User with ChangeNotifier{
    late String? name;
    late int? age;

  //set user name;
  setName(String name){
    this.name=name;
  }

  //set user age
  setAge(int age){
    this.age=age;
  }

}

UserList class


class UserList with ChangeNotifier{
  final List<User> _list=[];

  //add a new user to the list.
  void addUserToList(User user){
  _list.add(user);
  notifyListeners();
  }
  //return the private list of users.
List<User>getUsers() =>_list;


}

Here is the scenario. I want to insert a value from one page and view that inserted value on the second page. Look at the pictures below. On the first page,

  1. I insert the age and name values
  2. Assign those values in a User object instance (user.setName, user.setAge)
  3. Add that user object instance in a UserList list
  4. Use provider to provide that list.(Provider.of<UserList>(context).addUserToList(user);

First Page

first pic

First Page Code


void main() {
  runApp(

      MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) => UserList()),
            ChangeNotifierProvider(create: (context) => User()),
          ],
          child: const MyApp())
  
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}
class MyHomePage extends StatelessWidget {
  TextEditingController nameController = TextEditingController();
  TextEditingController ageController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    User user =User();
    return Scaffold(
      backgroundColor: Colors.grey[300],
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
              TextField(
                controller: nameController,
                decoration: const InputDecoration(
                  hintText: "Name",
                ),
              ),
            TextField(
              controller: ageController,
              decoration: const InputDecoration(
                hintText: "Age",
              ),
            ),
            ElevatedButton(onPressed: (){
             //providing userList
                user.setName(nameController.text); //setting user name
                user.setAge(int.parse(ageController.text)); // setting user age
               Provider.of<UserList>(context,listen: false).addUserToList(user); //providing the list of users
                nameController.text=""; //after insertion, clearing the text field
                ageController.text="";//after insertion, clearing the text field
                user=User(); // instantiating a new user object for the following insertion.
                Navigator.push(context, MaterialPageRoute(builder: (context)=>const ViewUser()));
            }, child: const Text("Submit"))

          ],
        ),
      ),
    );
  }
}


On the second page, display those inserted values in a ListView. Let's head to the main problem. Each item of ListViewis wrapped with a GestureDetector to be able to gain functionality.I hope everything is clear up to now. The problem is that; When I click on each item I want to return to the first page. But, this time the TextField shouldn't be empty. It must be replaced with the value of that item. For exmple. If I click on John Nash and 43. The First page must pop up with field value of that list item. To be able to do that I use another Provider to provide User object. But, I couldn't do it because of null safety it gives an error about the user object is null. Is there any idea that could be helpful.

Second Page

second page

Second Page code

class ViewUser extends StatelessWidget {
  const ViewUser({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    List<User> userList = Provider.of<UserList>(context).getUsers();
    return Scaffold(
      appBar: AppBar(
        title: const Text("Users List"),
      ),
      body: ListView.builder(
          padding: const EdgeInsets.all(8),
          itemCount: userList.length,
          itemBuilder: (BuildContext context, int index) {
            return Column(
              children: [
                const SizedBox(height: 15,),
                GestureDetector(
                  onTap: (){
                    Provider.of<User>(context,listen: false)
                        .setName(userList[index].name!);
                    Provider.of<User>(context,listen: false)
                        .setAge(userList[index].age!);
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>MyHomePage()));
                  },
                  child: Container(
                    height: 50,
                    color: Colors.amber,
                    child: Center(
                      child: Row(
                        children: [
                          Text("Name: " + userList[index].name!),
                          const SizedBox(
                            width: 40,
                          ),
                          Text("Age:" + userList[index].age.toString()),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            );
          }),
    );
  }
}

Demir
  • 799
  • 3
  • 16

1 Answers1

1

While you are using Navigator.push you can pass user as arguments.

GestureDetector(
  onTap: () {
    final user = userList[index];
    Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => MyHomePage(),
          settings: RouteSettings(
            arguments: user,
          )),
    );
  },

MyHomePage build method will be

 @override
  Widget build(BuildContext context) {
    User user = User();
    User? args = ModalRoute.of(context)?.settings.arguments as User?;

    if (args != null) {
      nameController.text = args.name ?? "";
      ageController.text = args.age.toString();
    }
    return Scaffold(....

You can also use Navigator.pop in this case.

GestureDetector(
  onTap: () {
    final user = userList[index];
    Navigator.pop(context, user);
  },

And to receive data on MyHomePage

onPressed: () async {
//....
final data = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ViewUser(),
  ),
);
if (data != null) {
  nameController.text = data.name ?? "";
  ageController.text = data.age.toString();
}

More about navigate-with-arguments.

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • Thank you much I have been looking for this answer for a week – Demir Jan 08 '22 at 17:41
  • You can also use `constructor`, you can check [this](https://stackoverflow.com/a/68605773/10157127) – Md. Yeasin Sheikh Jan 08 '22 at 17:43
  • Thank you but, when I implement a constructor I have to supply a user object each time. – Demir Jan 08 '22 at 19:03
  • you can use nullable user and check on build time like the way i did on arguments – Md. Yeasin Sheikh Jan 08 '22 at 20:46
  • I want to ask this question. I get the data on the first page. But now., when I edit the text field and save it, it creates a new list item on the second page. This isn't what I want. I want to overwrite the item on the second page. I couldn't think of a way to do it. Can you help me with that? – Demir Jan 08 '22 at 20:55
  • in that case , you can look for how to update data and include another field that will be your unique id – Md. Yeasin Sheikh Jan 08 '22 at 21:12
  • I am planning to pass multiple arguments to the first page such that the "user" and the "index" of the list. Now, since I have the index. I could replace it with that value? Does it sound like a good plan to you? – Demir Jan 08 '22 at 21:21
  • You can do that too, feel free to create separate question if you face any issue, including the efforts you put to solve the issue. – Md. Yeasin Sheikh Jan 08 '22 at 21:24