Click here to Skip to main content
15,867,834 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
So I'm trying to build a GridView.builder with pagination in Flutter to display a list of items, but I'm only able to display the 10 first items. I can see when I print the response.body that the next items are fetched when I reach the bottom, but I only get the circularIndicator and the next 10 items are not displayed.

What I have tried:

I followed this tutorial from the bloc team
https://bloclibrary.dev/#/flutterinfinitelisttutorial?id=post-events

Here the code for my Bloc:
Dart
const throttleDuration = Duration(seconds: 1);

EventTransformer<E> throttleDroppable<E>(Duration duration) {
  return (events, mapper) {
    return droppable<E>().call(events.throttle(duration), mapper);
  };
}

class NgoItemListBloc extends Bloc<NgoItemListEvent, NgoItemListState> {
  final BackendAPI backendAPI;

  NgoItemListBloc(this.backendAPI) : super(const NgoItemListState()) {
    on<LoadNgoItemList>(
      _onLoadNgoItemList,
      transformer: throttleDroppable(throttleDuration),
    );
  }

  Future<void> _onLoadNgoItemList(LoadNgoItemList event, Emitter<NgoItemListState> emit) async {
    if (state.hasReachedMax) return;
    try {
      if (state.status == ItemsStatus.initial) {
        final items = await backendAPI.fetchNgoItems(event.ngoId);
        return emit(state.copyWith(
          status: ItemsStatus.success,
          ngoItems: items,
          hasReachedMax: false,
        ));
      }
      final items = await backendAPI.fetchNgoItems(event.ngoId,state.ngoItems.length);
      emit(items.isEmpty
          ? state.copyWith(hasReachedMax: true)
          : state.copyWith(
              status: ItemsStatus.success,
              ngoItems: List.of(state.ngoItems)..addAll(items),
              hasReachedMax: false,
            ));
    } catch (_) {
      emit(state.copyWith(status: ItemsStatus.failure));
    }
  }
}

Here the code for my BlocProvider:
Dart
BlocProvider<NgoItemListBloc>(
                create: (context) => bloc
                  ..add(
                    LoadNgoItemList(ngo.id),
                  ),
                child: BlocBuilder<NgoItemListBloc, NgoItemListState>(
                  builder: (context, state) {
                    items = state.ngoItems;
                    switch (state.status) {
                      case ItemsStatus.failure:
                        return const Center(
                          child: Text('error to load!'),
                        );
                      case ItemsStatus.success:
                        if (items.isEmpty) {
                          return const Center(
                            child: Text('no items available!'),
                          );
                        }
                        return Container(
                          color: Colors.white,
                          child: GridView.builder(
                            controller: _scrollController,
                            shrinkWrap: true,
                            physics: const NeverScrollableScrollPhysics(),
                            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                              crossAxisSpacing: crossAxisSpacing,
                              childAspectRatio: aspectRatio,
                              crossAxisCount: crossAxisCount,
                            ),
                            itemCount: state.hasReachedMax ? items.length : items.length + 1,
                            itemBuilder: (BuildContext context, int index) {
                              return index >= items.length
                                  ? const MyCircularProgressIndicator()
                                  : _ItemListView(
                                      onTap: _handleItemTapped,
                                      item: items[index],
                                      ngoName: ngo.name,
                                    );
                            },
                          ),
                        );
                      default:
                        return const Center(
                          child: MyCircularProgressIndicator(),
                        );
                    }
                  },
                ),
              ),


and I think the problem is coming from the _onScroll function but I'm not really sure.

Dart
void _onScroll() {
    if (_isBottom) {
      BlocProvider.of<NgoItemListBloc>(context)
          .add(LoadNgoItemList(ngo.id));
    }
  }

API call:
Dart
Future<List<Item>> fetchNgoItems(int ngoId, [int startIndex = 0]) async {
    final http.Response response =
        await _httpClient.get("/ngo/$ngoId/item?page=$startIndex&size=$maxItemsPerPage");
    print(response.body);
    return jsonDecode(utf8.decode(response.bodyBytes))['content']
        .map<Item>((json) => Item.fromJson(json))
        .toList();
  }

Thank you in advance for your help!
Posted
Updated 2-Aug-22 23:27pm
Comments
wseng 2-Aug-22 12:00pm    
check startIndex. Did startIndex value increase when page scrolled?
Digiyang 3-Aug-22 5:27am    
Thank you for your answer! I also think the problem is coming from there, so this is what I did.
Future<List<Item>> fetchNgoItems(int ngoId, int startIndex) async {
    final http.Response response =
        await _httpClient.get("/ngo/$ngoId/item?page=$startIndex&size=$maxItemsPerPage");
    print(response.body);
    return jsonDecode(utf8.decode(response.bodyBytes))['content']
        .map<Item>((json) => Item.fromJson(json))
        .toList();
  }

so I included the index as a parameter in the bloc_event, initialised to 0 at the first call of the bloc and then incremented it.
try {
      if (state.status == ItemsStatus.initial) {
        final items = await backendAPI.fetchNgoItems(event.ngoId, event.index);
        return emit(state.copyWith(
          status: ItemsStatus.success,
          ngoItems: items,
          hasReachedMax: false,
        ));
      }
      final items = await backendAPI.fetchNgoItems(event.ngoId, event.index);
      emit(items.isEmpty
          ? state.copyWith(hasReachedMax: true)
          : state.copyWith(
              status: ItemsStatus.success,
              ngoItems: List.of(state.ngoItems)..addAll(items),
              hasReachedMax: false,
            ));
    }
Builder(builder: (context) {
        return BlocBuilder<NgoItemListBloc, NgoItemListState>(
          bloc: bloc
            ..add(
              LoadNgoItemList(ngo.id, pageIndex),
            ),


void _onScroll() {
    if (_isBottom) {
      context.read<NgoItemListBloc>().add(LoadNgoItemList(ngo.id, pageIndex += 1));
    }
  }


I should get:

{"content":[],"pageable":{"sort":{"empty":true,"sorted":false,"unsorted":true},**"offset":70**,**"pageNumber":7**,"pageSize":10,"paged":true,"unpaged":false},"totalPages":7,"totalElements":63,"last":true,"size":10,"number":7,"sort":{"empty":true,"sorted":false,"unsorted":true},"numberOfElements":0,"first":false,"empty":true}

but instead, I'm getting:
flutter: {"content":[],"pageable":{"sort":{"empty":true,"sorted":false,"unsorted":true},**"offset":150**,**"pageNumber":15,**"pageSize":10,"paged":true,"unpaged":false},"totalPages":7,"totalElements":63,"last":true,"size":10,"number":15,"sort":{"empty":true,"sorted":false,"unsorted":true},"numberOfElements":0,"first":false,"empty":true}


any idea what I'm doing wrong ?
wseng 3-Aug-22 23:58pm    
print out startIndex in fetchNgoItems. What value you got?
Digiyang 5-Aug-22 3:31am    
Hi I already solved my issue thank you :D
Should I post it here for others ?
wseng 6-Aug-22 12:36pm    
Glad to hear that. Yes, in case it might help someone else :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900