Search code examples
flutterflutter-provider

Flutter provider to pass a singe object out of list to the child view


I have a page where it shows ListView that contains list of schools. So I load all the schools (in initState() method) when the user clicks on My Schools.

Now I want to pass the School object when user clicks on a school's in the ListView and show the edit school page.

I want to use the provider patter for this so I can pass a single school object to the edit page and once user done with edit and press back, it automatically reflects the updated school in the ListView.

I am really confused with how to pass a single object from a list to the edit page. Following is my code where I have model, provider and state classes. As I am not getting how to access the school object in the edit page I have not created it yet.

I do not want to use the constructor to pass the school object to edit.

// School model class
class SchoolModel {
  String name;
  double points; 
}

// school provider
class SchoolProvider with ChangeNotifier {
   School _school;
   School get school => _school;

   set School(School value) {
       _school = value;
        notifyListeners();
   }
}

// School list page
class ListSchool extends StatefulWidget {
   @override
  _ListSchoolState createState() => _ListSchoolState();
}

// List page state
class _ListSchoolState extends State<ListSchool> {
    List<School> _schools;
    @override
    void initState() {
       _schools = FirebaseCall(); // loading schools
    }
}

@override
Widget build(BuildContext context) {
return Scaffold(
   body: MultiProvider(
            providers: [
              ChangeNotifierProvider(
                create: (context) => SchoolProvider(),
              ),
            ],
             child: ListView.builder(
                itemCount: _schools.length,
                itemBuilder: (BuildContext ctxt, int index) {
                   return ListTile(
                       title: Text(_schools[index].name);
                       onTap() {
                          // Open Edit page and pass the clicked school object to edit page
                       }
                   );
                }
             )
         )
);

Thank you


Solution

  • I think you need to change your change notifier, to be the list that you want to update.

    class SchoolsProvider with ChangeNotifier {
       List<School> _schools;
       School get schools => _schools;
    
       SchoolProvider(this._schools = const []);
    
       void addSchool(School newSchool) { 
         _schools.add(newSchool); 
         notifyListeners();
       }
    
       void removeShool(String schoolName) {
         _schools.removeWhere((s) => s.name == schoolName);
         notifyListeners();
       }
    
       void updateSchool(String shoolName, double points) {
         _schools.removeWhere((s) => s.name == schoolName);
         addSchool(School(schoolName, points));
       }
    }
    

    When you tap on the ListTile you just push the new page, and pass in the desired school.

    Consumer<SchoolsProvider>(
        builder: (_, schools, __) => ListView.builder(
         itemCount: schools.length,
         itemBuilder: (BuildContext ctxt, int index) {
          return ListTile(
            title: Text(schools[index].name),
            onTap() {
               Navigator.push(context, MaterialRoutePage(
                 context,
                 builder: (_) => YourNewPage(school: schools[index]),
               ));      
            },
          );
        },
      ),
    ),
    

    From the new page, you can just access the methods declared in the Provider, this will update the listeners

    
    class NewPage extends StatelessWidget {
    
      final School school;
     
      NewPage({this.school});
    
      ...
      
      //Here you can perform any action on the schools Provider
      // It will notify it's listeners (Consumer) so it gets updated
      schools[index].add
      schools[index].remove
      schools[index].update  
    
      ...