Click here to Skip to main content
15,885,366 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)

  Print Answers RSS
Top Experts
Last 24hrsThis month


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