'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 1:[1]

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.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1