Flutter: How to trigger a bloc event in the controller?
Asked Answered
C

2

2

In summary I want the "context.read().add(EnabledEvent())" to work from the controller itself or some other alternative I can use to trigger an event from the controller and update the state:

class SplashCtrl extends GetxController {

  @override
  void onReady() {
    User user = loadUser();
    if (user.isExampleEnabled) {
      context.read<ExampleBloc>().add(EnabledEvent());
    }
  }

Another thing I tried was this:

ExampleBloc testBloc = ExampleBloc();
testBloc.add(TestEvent());

in the controller, and it does seem to trigger the event, but the UI doesn't update with the state change. I seem to really need the Context for that to change. Any ideas?

MORE DETAILS AND CONTEXT:

I want to trigger bloc events not just in the page itself, but in the page's controller!

So I have pages in my flutter app with each view having a controller set up like this:

class SplashPage extends GetView<SplashCtrl> {
  @override
  Widget build(BuildContext context) {
    Get.lazyPut(() => SplashCtrl());
    return Scaffold(...);
  }
}

SplashCtrl is the controller for this page. This splash view page is one of the first pages that loads it runs functions when it's added and ready (basically instantly), such as checking if the user is logged in and loading their data to the app, like this:

class SplashCtrl extends GetxController {

  @override
  void onReady() {
    // run stuff here
  }

I have been able to get away with creating lambda functions in the pages and triggering events based on what they do and toggle like this:


IconSwitchedButtonUi(
  value: state.isExampleOn,
  icon: Images.toggleIcon,
  title: "Is Example enabled?",
  onChanged: (value) {
  if (value) {
    context.read<ExampleBloc>().add(EnabledEvent());
    } else {
    context.read<ExampleBloc>().add(DisabledEvent());
    }
  },
),

but now I need a bloc event to trigger and change the state a bit if a user has a certain value for one of their fields. How do I do that? How do I trigger an event from within the controller? The "context.read" doesn't work because the controller doesn't have context, or does it?

Cate answered 27/4, 2022 at 12:51 Comment(1)
Haven't you asked yourself wtf are you doing since you are using BLoC and GetX?)Taveras
C
-1

I was able to resolve this by adding a late BuildContext to my controller:

class SplashCtrl extends GetxController {

  late BuildContext context;

  @override
  void onReady() {
    // run stuff here
  }

After that, in the page itself, I passed the context like this:

class SplashPage extends GetView<SplashCtrl> {
  @override
  Widget build(BuildContext context) {
    controller.context = context;
    Get.lazyPut(() => SplashCtrl());
    return Scaffold(...);
  }
}

Then I was able to use the context within the controller itself!!

if (value) {
    context.read<ExampleBloc>().add(EnabledEvent());
    } else {
    context.read<ExampleBloc>().add(DisabledEvent());
    }
  },
Cate answered 27/4, 2022 at 22:11 Comment(1)
Passing BuildContext is an extremely bad practice and is very error-prone. Avoid it at all costs.Charleen
E
3

ExampleBloc testBloc = ExampleBloc(); testBloc.add(TestEvent());

This does not work because you were declaring totally new instance of bloc that wasnt connected by any BlocProvider to your widget tree, hence there is no way you could trigger this bloc events that would emit state your BlocBuilder could react to. Since there is no bloc provided to widget tree read() wont find this bloc.

In order for this work you need to:

Pass BuildContext that have some Bloc or Cubit provided by BlocProvider
void foo(BuildContext context) {
  User user = loadUser();
  if (user.isExampleEnabled) {
    context.read<ExampleBloc>().add(EnabledEvent());
  }
}
..or listen to bloc changes directly inside controller
class SplashCtrl extends GetxController {
  SplashCtrl(MyBloc bloc) {
    bloc.stream.listen((event) {
    // React to bloc changes here
    if (event is MyBlocEvent) {
      // Do something
      }
    }
  }
}

Remember that even in this approach bloc instance given to SplashCrtl constructor must be the same that is provided by BlocProvider to a widget tree in order for this to work.

Excusatory answered 27/4, 2022 at 21:39 Comment(0)
C
-1

I was able to resolve this by adding a late BuildContext to my controller:

class SplashCtrl extends GetxController {

  late BuildContext context;

  @override
  void onReady() {
    // run stuff here
  }

After that, in the page itself, I passed the context like this:

class SplashPage extends GetView<SplashCtrl> {
  @override
  Widget build(BuildContext context) {
    controller.context = context;
    Get.lazyPut(() => SplashCtrl());
    return Scaffold(...);
  }
}

Then I was able to use the context within the controller itself!!

if (value) {
    context.read<ExampleBloc>().add(EnabledEvent());
    } else {
    context.read<ExampleBloc>().add(DisabledEvent());
    }
  },
Cate answered 27/4, 2022 at 22:11 Comment(1)
Passing BuildContext is an extremely bad practice and is very error-prone. Avoid it at all costs.Charleen

© 2022 - 2024 — McMap. All rights reserved.