How do I trigger bloc event from addListener?

787

After researching for some days, I found that we have to specify BuildContext rather than make it dynamic. As during runtime this field will check the type, but will not check during compilation time. This was the issue that couldn't generate a read function and trigger the bloc event during compilation time when the setupScrollController function was called.

Before

before

After

After

Reference: https://blog.csdn.net/Mr_Tony/article/details/111738933

Share:
787
Prajun Lungeli
Author by

Prajun Lungeli

Updated on January 02, 2023

Comments

  • Prajun Lungeli
    Prajun Lungeli over 1 year

    I'm trying to fetch data when I reach the last item scrolling the list view, but the event isn't triggering. As soon as I end up with the last item, the scrollController is used for listening to the scrolling activity and should trigger the bloc event to fetch more data but it isn't happening.

    Here is the code for that part:

    class OrderHistoryPage extends StatelessWidget {
      const OrderHistoryPage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return BlocProvider(
          create: (context) => getIt<OrderHistoryWatcherBloc>()
            ..add(const OrderHistoryWatcherEvent.fetchOrderHistory()),
          child: PageBuilder(),
        );
      }
    }
    
    class PageBuilder extends StatelessWidget {
      final scrollController = ScrollController();
    
      PageBuilder({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return BlocBuilder<OrderHistoryWatcherBloc, OrderHistoryWatcherState>(
            builder: (context, state) {
          if (state.isProcessing) {
            return const Scaffold(
              body: CustomLoadingIndicator(),
            );
          } else {
            return state.failureOrSuccess?.fold(
                    (l) => Scaffold(
                          body: FailedContainer(
                            onTap: () =>
                                context.read<OrderHistoryWatcherBloc>().add(
                                      const OrderHistoryWatcherEvent
                                          .fetchOrderHistory(),
                                    ),
                          ),
                        ), (r) {
                  setupScrollController(context, r.next);
    
                  var ordersList = r.results;
    
                  if (state.searchKey != null) {
                    ordersList = ordersList
                        .where((element) => element.id
                            .toString()
                            .toLowerCase()
                            .contains(state.searchKey!.toLowerCase()))
                        .toList();
                  }
    
                  return MainScaffold(
                    requiredAppBar: true,
                    pageName: pageName,
                    requiredAppDrawer: true,
                    body: Column(
                      children: [
                        CustomSearchBox(
                          icon: Icons.search_sharp,
                          hintText: 'Search Orders by Id',
                          onChanged: (v) {
                            context
                                .read<OrderHistoryWatcherBloc>()
                                .add(OrderHistoryWatcherEvent.searchKey(v));
                          },
                        ),
                        sizedBoxedSmall,
                        Expanded(
                          child: RefreshIndicator(
                            onRefresh: () async {
                              context.read<OrderHistoryWatcherBloc>().add(
                                  const OrderHistoryWatcherEvent
                                      .fetchOrderHistory());
                            },
                            child: ordersList.isNotEmpty
                                ? ListView.builder(
                                    physics: const AlwaysScrollableScrollPhysics(),
                                    controller: scrollController,
                                    itemBuilder: (context, index) {
                                      if (index < ordersList.length) {
                                        return OrderListTile(
                                            orderId: ordersList[index].id,
                                            createdDateTime:
                                                ordersList[index].created,
                                            totalPrice: ordersList[index].total,
                                            orderStatus: ordersList[index].status);
                                      } else {
                                        Timer(const Duration(milliseconds: 30), () {
                                          scrollController.jumpTo(scrollController
                                              .position.maxScrollExtent);
                                        });
    
                                        return const Center(
                                            child: CircularProgressIndicator());
                                      }
                                    },
                                    itemCount: ordersList.length +
                                        (state.isLoading ? 1 : 0),
                                  )
                                : const Text('Search result not found'),
                          ),
                        ),
                      ],
                    ),
                  );
                }) ??
                Container();
          }
        });
      }
    
      void setupScrollController(context, String? url) {
        scrollController.addListener(() {
          if (scrollController.position.atEdge) {
            if (scrollController.position.pixels != 0) {
              debugPrint('from order history page : $url');
              context
                  .read<OrderHistoryWatcherBloc>()
                  .add(OrderHistoryWatcherEvent.fetchOrderHistory(url: url));
            }
          }
        });
      }
    }
    

    Here is the error log:

    ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════ The following NoSuchMethodError was thrown while dispatching notifications for ScrollController: Class 'StatefulElement' has no instance method 'read'. Receiver: Instance of 'StatefulElement' Tried calling: read()

    When the exception was thrown, this was the stack: #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:63:5) #1 PageBuilder.setupScrollController. (package:mitho_food_vendor/features/order/presentation/pages/order_history_page.dart:130:16) #2 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24) #3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:308:24) #4 ScrollPosition.notifyListeners (package:flutter/src/widgets/scroll_position.dart:968:11) #5 ScrollPosition.forcePixels (package:flutter/src/widgets/scroll_position.dart:380:5) #6 ScrollPositionWithSingleContext.jumpTo (package:flutter/src/widgets/scroll_position_with_single_context.dart:198:7)
    #7 ScrollController.jumpTo (package:flutter/src/widgets/scroll_controller.dart:173:16) #8 PageBuilder.build.... (package:mitho_food_vendor/features/order/presentation/pages/order_history_page.dart:101:56) (elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)

    The ScrollController sending notification was: ScrollController#0c24c(one client, offset 34.4)

  • Brian Formento
    Brian Formento over 2 years
    I would recommend not using images as code snippets, if you can, try to write the code yourself, apart from being cleaner, it helps people who search by code :)
  • Prajun Lungeli
    Prajun Lungeli over 2 years
    Thanks, Brian Formento for the suggestion, I'll make sure to write the code next time.