Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle BlocProvider with Modal Bottom Sheet

I have a statefull widget with a Gesture detector within a Bloc Provider.

  @override
  Widget build(BuildContext context) {
    return RepositoryProvider.value(
      value: _authRepository,
      child: BlocProvider(
        create: (context) => AuthBloc(authRepository: AuthRepository()),
        child: Scaffold(
          body: GestureDetector(
            onTap: () {
              showSignInBottomSheet(context);
            },
          ),
        ),
      ),
    );
  }
}

On tap I want to show a modal botttom sheet, which I wish could access the Bloc I created previously.

I've been told I should wrap the modal builder with BlocProvider.value for that purpose.

showSignInBottomSheet(BuildContext context) => showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    backgroundColor: Colors.white,
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.vertical(top: Radius.circular(0.0)),
    ),
    builder: (context) {
      return BlocProvider.value(
          value: BlocProvider.of<AuthBloc>(context, listen: false),
          child: Container(
              padding: const EdgeInsets.only(top: 40),
              height: MediaQuery.of(context).size.height,
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 15.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        springWidget(() {
                          Navigator.of(context).pop();
                        },
                            const Icon(
                              CupertinoIcons.xmark,
                              size: 20,
                            )),
                      ],
                    ),
                  ),
                  Expanded(
                      child: Container(
                    color: Colors.red,
                  )),
                ],
              )));
    });

But Im still getting this error.


  BlocProvider.of() called with a context that does not contain a AuthBloc.

        No ancestor could be found starting from the context that was passed to BlocProvider.of<AuthBloc>().

I'm new to that bloc state management thing, So I really don't know what is going wrong.

Help please before I get overflowed.

like image 325
Toby Yhs Avatar asked Sep 19 '25 08:09

Toby Yhs


1 Answers

Rename the builder context from the showModalBottomSheet so that your BlocProvider use the correct context. Perhaps change:

 builder: (context) {
      return BlocProvider.value(
          value: BlocProvider.of<AuthBloc>(context, listen: false),

To:

 builder: (innerContext) {
      return BlocProvider.value(
          value: BlocProvider.of<AuthBloc>(context, listen: false),

Here is a full working example:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo',
      home: BlocProvider(
        create: (context) => DemoCubit(),
        child: const FirstPage(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SO question 75774451'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () => showModalBottomSheet(
                  context: context,
                  builder: (innerContext) => BlocProvider.value(
                    value: context.read<DemoCubit>(),
                    child: Column(
                      children: [
                        BlocBuilder<DemoCubit, int>(
                          builder: (context, state) {
                            return Text('Current state: $state');
                          },
                        ),
                        ElevatedButton(
                          onPressed: () => context.read<DemoCubit>().inc(),
                          child: const Text('Press me'),
                        )
                      ],
                    ),
                  ),
                ),
            child: Text('Show modal - Current state: ${context.watch<DemoCubit>().state}')),
      ),
    );
  }
}

class DemoCubit extends Cubit<int> {
  DemoCubit() : super(0);
  void inc() => emit(state + 1);
}
like image 164
Robert Sandberg Avatar answered Sep 22 '25 05:09

Robert Sandberg