Search code examples
flutterdartflutter-provider

How to pass generic provider to child?


I want to create a universal alert that I will use several times in my app.

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

  @override
  Widget build(BuildContext context) {
    final model = Provider.of<IncomeViewModel>(context, listen: true).state;

    return AlertDialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(40),
      ),

Problem is that I can not figure out how to pass type of parent ChangeNotifier

                  showDialog<String>(
                    context: context,
                    builder: (_) =>
                        ChangeNotifierProvider<IncomeViewModel>.value(
                      value: view,
                      child: const SelectIconAlertDialogWidget(),
                    ),
                  );

I have a lot of ViewModels that will use this alert so dont want to repeat this code and write generic Alert that I can use with any ViewModel. How can I achieve this?


Solution

  • Create some abstract class with methods or fields you want to have for all your view models you use for that dialog

    abstract class AbstractViewModel{
      void doStuff();
    }
    

    Implement this class for your view models

    class MyViewModel1 implements AbstractViewModel{
       @override
       void doStuff (){ print("from MyViewModel1");}
    }
    

    Add type parameter for your dialog class

     class SelectIconAlertDialogWidget<T extends AbstractViewModel> extends StatelessWidget {
      const SelectIconAlertDialogWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // and you can use generic type T like this:
        final model = Provider.of<T>(context, listen: true);
        model.doStuff();
    
        return AlertDialog(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(40),
          ),
    

    And call it passing type parameter SelectIconAlertDialogWidget<MyViewModel1>()

    showDialog<String>(
                        context: context,
                        builder: (_) =>
                            ChangeNotifierProvider<MyViewModel1>.value(
                          value: view,
                          child: const SelectIconAlertDialogWidget<MyViewModel1>(),
                        ),
                      );
    

    On build method of your dialog widget it will print "from MyViewModel1". Hope you got the concept of abstraction.