10

We want to show an AlertDialog after some asynchronous processing such as network processes.

When calling 'showAlertDialog ()' from an external class, I want to call it without context. Is there a good way?

class SplashPage extends StatelessWidget implements SplashView {
  BuildContext _context;
  @override
  Widget build(BuildContext context) {
    this._context = context;
    ...
  }

I've considered the above method, but I'm worried about side issues.

Help

My current code

class SplashPage extends StatelessWidget implements SplashView {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: MyStoreColors.eats_white1_ffffff,
      body: Center(
        child: new SvgPicture.asset('assets/ic_splash.svg'),
      ),
    );
  }

  @override
  void showAlertDialog() {

    showDialog<void>(
      context: /*How to get context?*/,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Not in stock'),
          content: const Text('This item is no longer available'),
          actions: <Widget>[
            FlatButton(
              child: Text('Ok'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }

  @override
  void moveToHomeContainer() {
  }

  @override
  void moveToLoginContainer() {
  }
}

kyeonghwan
  • 424
  • 3
  • 7
  • 21
  • and where will you use `showAlertDialog`? You could pass a `context` as parameter – Julien Lachal Oct 24 '19 at 14:35
  • Yea, why are you not using `showAlertDialog(BuildContext context)` ? – TWL Oct 24 '19 at 16:53
  • I try to use an architecture similar to MVP. In this page, I want to check the app version when the view is bound to the presenter. And I want to output the error message about the version check to `view.showAlertDialog()` in the presenter. – kyeonghwan Oct 25 '19 at 00:04
  • Are you talking about calling `presenter.checkAppVersion(context)` in `build()`? – kyeonghwan Oct 25 '19 at 00:14

3 Answers3

7

To show an AlertDialog you need the context, but in StatelessWidget you do not have access to it directly as in StatefulWidget.

Few options are [1]:

  • passing it as GlobalKey [2]
  • passing build context as parameter to any other function inside StatelessWidget
  • use a service to inject the dialog without context [3]

Cheers.

J. Pablo García
  • 499
  • 7
  • 19
3

You should trigger rebuild when the async event complete, either convert your widget to StatefulWidget and call setState() or use a state management solution like Bloc.

For example using StatefulWidget your code will look like this:

class SplashPage extends StatefulWidget {
  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> implements SplashView {

  bool _asynOpDone = false;

  /// Call this when the async operation is done.
  void _onAsynOpDone() => setState(() => _asyncOpDone = true);

  @override
  Widget build(BuildContext context) {
    if (_asyncOpDone) showAlertDialog(context);

    return Scaffold(
      ...,
      ///
    );
  }

  @override
  void showAlertDialog(BuildContext context) {
    showDialog<void>(
      context: context,
      builder: ...,
    );
  }
}
Gan Quan
  • 449
  • 5
  • 13
  • 1
    This page is an intro screen with only one image view. Once built, views do not need to be rebuilt. By the way, should I use StatefulWidget to bring up an AlertDialog? I thought there was another good way to ask. – kyeonghwan Oct 25 '19 at 00:11
1

You can apply Builder pattern concept to simplify this.

There is a little example here.

button_builder.dart

itmarck
  • 51
  • 2