Vincenzo
Vincenzo

Reputation: 6448

Using a List value index stored in a variable trows an error while using List value directly works fine Flutter

In my screen I have on half a screen a ListView that shows all booking records from local db which get stored in a List<Booking> bookings, on the other half I have a detailed view for the selected booking item from the ListView. In the detailed view I also have 3 buttons that send push notification event to bloc which takes a booking as a input parameter. To be able to have a reference to the Booking displayed in the details view I store the ListView item index in a int selectedBooking = 0; variable when selecting an item from the ListView. The problem is that sending the notification event from the buttons using that variable throws an error. I tried sending it directly from ListView item selection and it get sent just fine. I'm sure it's not null as I print bookings[selectedBooking] before sending the notification and prints fine, but some how makes the notification sending event throw an error that doesn't get printed in the catch scope.

The only difference is that in the ListView item's onTap: I take the booking directly come the List<Booking> with booking[index] while in the button's onPressed: I use the variable that stores that same index bookings[selectedBooking]..

This is the screen build:

Widget build(BuildContext context) {
    return MultiBlocProvider(
        providers: [
          BlocProvider<BookingBloc>(
            create: (context) =>
                BookingBloc(widget.user)..add(LoadBookings(user: widget.user)),
          ),
          BlocProvider<PushNotificationBloc>(
            create: (context) => PushNotificationBloc(),
          ),
        ],
        child: MultiBlocListener(
          listeners: [
            BlocListener<BookingBloc, BookingState>(
                listener: (BuildContext context, BookingState state) {
              if (state is LoadedBookings) {
                setState(() {
                  bookings = state.bookings;
//                  isSelected = state.isSelected;
//                  Timer(Duration(milliseconds: 50), () {
//                    scrollToIndex(bookings);
//                  });
                });
              }
              if (state is BookingDetails) {
                setState(() {
                  bookingId = state.booking.bookingId;
                  bookingDate = dateOnlyFormat.format(
                      DateTime.fromMillisecondsSinceEpoch(
                          state.booking.bookingStart));
                  bookingStart = timeFormat.format(
                      DateTime.fromMillisecondsSinceEpoch(
                          state.booking.bookingStart));
                  bookingEnd = timeFormat.format(
                      DateTime.fromMillisecondsSinceEpoch(
                          state.booking.bookingEnd));
                  customerName = state.booking.customerName;
                  works = state.booking.worksNameList;
                  bookingPrice = state.booking.bookingPrice;
                  collectedOnDate = state.booking.collectedOnDate;
                });
              }
            }),
          ],
          child: Container(

This is the ListView item's onTap:

onTap: () {
  // sending push here does work...
  //BlocProvider.of<PushNotificationBloc>(
  //context).add(
  //BookingStartedPushNotification(
  //booking: bookings[index]));
  if (isSelected[index] == false) {
    //store booking in a variable for sending notifications
    selectedBooking = index;
    print(
      'selected booking is ${bookings[selectedBooking].toMap().toString()}');
    //load selected booking
    BlocProvider.of<BookingBloc>(context).add(
      LoadBookingDetails(
        DateTime.fromMillisecondsSinceEpoch(
          bookings[index].bookingStart),
      ),
    );
  } else {
    setState(() {
      //selectedBooking = null;
      print(
        'selected booking is ${bookings[selectedBooking].toMap().toString()}');
      bookingId = '';
      bookingDate = '';
      bookingStart = '';
      bookingEnd = '';
      customerName = '';
      works = '';
      bookingPrice = '';
      bookingState = '';
      collectedOnDate = '';
    });
  }
setState(() {
  //invert isSelected value
  isSelected[index] = !isSelected[index];
}

and this is the button onPressed:

onPressed: () {
  print("Started button is been clicked");
  //cache.play(
  //'tableViewClose.mp3');
  print(
    'selected booking is : ${bookings[selectedBooking].toMap().toString()}');
  try {
    BlocProvider.of<PushNotificationBloc>(
      context)
    .add(BookingStartedPushNotification(
      booking:
      bookings[selectedBooking]));
  } catch (e) {
    print('Error is : $e');
  }

  BlocProvider.of<BookingBloc>(context).add(
    UpdateBookingState(
    user: widget.user,
    cityDb: widget.cityDb,
    regionDb: widget.regionDb,
    booking:
    bookings[selectedBooking],
    state: 'Started'));
}

Upvotes: 0

Views: 32

Answers (1)

ZeRj
ZeRj

Reputation: 1708

Your context in the Buttons onPressed probably does not have an PushNotificationBloc or BookingBloc available. Your widget tree is inside one big build method and never gets interupted by a builder. So the context used in the onPressed method is the one passed through Widget build(BuildContext context) at the top, that does not have the MultiBlocProvider as ancestor.

Have a look at the BlocProvider.of() fails to find Bloc section here: https://bloclibrary.dev/#/faqs

Either insert a Builder somewhere in the widget tree, or even better split your build function into multiple widgets. This will also make your code a lot easier to read.

Upvotes: 1

Related Questions