Flutter / BLoC - BlocProvider.of() called with a context that does not contain a Bloc of type ArticlesBloc

Viewed 4006

I'm developing a new Flutter Mobile app using the BLoC pattern. But I've got a problem and I don't find the solution yet. I've got three widgets :

  • The first one is my home page with a drawer
  • Thanks to the drawer, I can navigate to my second widget, an article list
  • And one last widget : article details (I can reach it with a tap on an article in the list)

My problem is between the second and the third. When I tap on an article, I've an error : BlocProvider.of() called with a context that does not contain a Bloc of type ArticlesBloc.

I've got this in my MaterialApp routes attribute

MyRoutes.articleList: (context) => BlocProvider<ArticlesBloc>(
              create: (context) => ArticlesBloc()..add(ArticlesLoaded()),
              child: ArticlesScreen(),
            ),

This is my article list body :

body: BlocBuilder<ArticlesBloc, ArticlesState>(
        builder: (BuildContext buildContext, state) {
          if (state is ArticlesLoadSuccess) {
            final articles = state.articles;
            return ListView.builder(
              itemCount: articles.length,
              itemBuilder: (BuildContext context, int index) {
                final article = articles[index];
                return ArticleItem(
                    onTap: () {
                      Navigator.of(buildContext).push(
                        MaterialPageRoute(builder: (_) {
                          return ArticleDetailScreen(id: article.id);
                        }),
                      );
                    },
                    article: article);
              },
            );
          }
        },
      ),

And my article details page :

@override
  Widget build(BuildContext context) {
    return BlocBuilder<ArticlesBloc, ArticlesState>(builder: (context, state) {
      final Article article = (state as ArticlesLoadSuccess)
          .articles
          .firstWhere((article) => article.id == id, orElse: () => null);
      return Scaffold(
        appBar: AppBar(
          title: Text(article.reference + ' - Article details'),
        ),
        body: id == null
            ? Container()
            : Padding(
                padding: EdgeInsets.all(16.0),
                child: ListView(
                  children: [
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Hero(
                                tag: '${article.id}__heroTag',
                                child: Container(
                                  width: MediaQuery.of(context).size.width,
                                  child: Text(
                                    article.designation,
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
      );
    });
  }

Please heeeelp ^^

Edit 1 : I find a solution but I don't know if it's the right way. Instead of only pass the id to the details screen, I pass the complete article so I can directly return the Scaffold without the BlocBuilder

1 Answers

You need to provide your bloc to your new route with ArticleDetailScreen. Like this:

MaterialPageRoute(builder: (_) {
  return BlocProvider.value(
    value: BlocProvider.of<ArticlesBloc>(context),
    child: ArticleDetailScreen(id: article.id),
  );
})
Related