Home > database >  Flutter rest api getting double result in pagination
Flutter rest api getting double result in pagination

Time:07-24

I am using my rest API to get data in the app I used HTTP I write some code for pagination. the pagination is working good but when my all data get returned it's not show a message to all data is returned else its starts duplicate data from the top again. it's creating the duplicate data again pagination not stopping its returning the same data again and agin

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'dart:convert';
import "package:http/http.dart" as http;
import 'package:voterlist/Widgets/adhelper.dart';
import 'package:voterlist/Widgets/constant.dart';
import 'package:voterlist/Widgets/skeleton.dart';
import 'package:voterlist/Widgets/widget.dart';

class Jobs extends StatefulWidget {
  const Jobs({Key? key}) : super(key: key);

  @override
  State<Jobs> createState() => _JobsState();
}

class _JobsState extends State<Jobs> {
  final adManager = AdManager();

  // We will fetch data from this Rest api
  final _baseUrl = 'api';

  // At the beginning, we fetch the first 20 posts
  int _page = 0;
  // you can change this value to fetch more or less posts per page (10, 15, 5, etc)
  final int _limit = 15;

  // There is next page or not
  bool _hasNextPage = true;

  // Used to display loading indicators when _firstLoad function is running
  bool _isFirstLoadRunning = false;

  // Used to display loading indicators when _loadMore function is running
  bool _isLoadMoreRunning = false;

  // This holds the posts fetched from the server
  List _posts = [];

  // This function will be called when the app launches (see the initState function)
  void _firstLoad() async {
    setState(() {
      _isFirstLoadRunning = true;
    });
    try {
      final res = await http.get(Uri.parse("$_baseUrl?$_page&$_limit"));
      setState(() {
        _posts = json.decode(res.body);
      });
    } catch (err) {
      if (kDebugMode) {
        print('Something went wrong');
      }
    }

    setState(() {
      _isFirstLoadRunning = false;
    });
  }

  // This function will be triggered whenver the user scroll
  // to near the bottom of the list view
  void _loadMore() async {
    if (_hasNextPage == true &&
        _isFirstLoadRunning == false &&
        _isLoadMoreRunning == false &&
        _controller.position.extentAfter < 300) {
      setState(() {
        _isLoadMoreRunning = true; // Display a progress indicator at the bottom
      });
      _page  = 1; // Increase _page by 1
      try {
        final res = await http.get(Uri.parse("$_baseUrl?$_page&$_limit"));

        final List fetchedPosts = json.decode(res.body);
        if (fetchedPosts.isNotEmpty) {
          if (!fetchedPosts.contains(fetchedPosts)) {
            setState(() {
              _posts.addAll(fetchedPosts);
            });
          }
        } else {
          // This means there is no more data
          // and therefore, we will not send another GET request
          setState(() {
            _hasNextPage = false;
          });
        }
      } catch (err) {
        if (kDebugMode) {
          print('Something went wrong!');
        }
      }

      setState(() {
        _isLoadMoreRunning = false;
      });
    }
  }

  // The controller for the ListView
  late ScrollController _controller;

  @override
  void initState() {
    super.initState();
    _firstLoad();
    _controller = ScrollController()..addListener(_loadMore);
    adManager.addAds(true, true, true);
    adManager.showInterstitial();
  }

  @override
  void dispose() {
    _controller.removeListener(_loadMore);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: headerNav(title: "Sarkari Naukri"),
      body: _isFirstLoadRunning
          ? ListView.separated(
              itemCount: 5,
              itemBuilder: (context, index) => const NewsCardSkelton(),
              separatorBuilder: (context, index) =>
                  const SizedBox(height: defaultPadding),
            )
          : Column(
              children: [
                Expanded(
                  child: ListView.separated(
                    controller: _controller,
                    itemCount: _posts.length,
                    itemBuilder: (_, index) => JobCard(
                      onPress: () {
                        FlutterWebBrowser.openWebPage(
                          url: _posts[index]['moredetils'],
                          safariVCOptions: const SafariViewControllerOptions(
                            barCollapsingEnabled: true,
                            preferredBarTintColor: Colors.green,
                            preferredControlTintColor: Colors.amber,
                            dismissButtonStyle:
                                SafariViewControllerDismissButtonStyle.close,
                            modalPresentationCapturesStatusBarAppearance: true,
                          ),
                        );
                      },
                      image: _posts[index]['imagelink'],
                      state: _posts[index]['state'],
                      title: _posts[index]['title'],
                      subtitle: _posts[index]['totalpost'].toString(),
                    ),
                    separatorBuilder: (BuildContext context, int index) {
                      if ((index   1) % 4 == 0) {
                        return Container(
                          width: adManager.getBannerAd()?.size.width.toDouble(),
                          height:
                              adManager.getBannerAd()?.size.height.toDouble(),
                          child: AdWidget(ad: adManager.getBannerAd()!),
                        );
                      }
                      return const SizedBox();
                    },
                  ),
                ),

                // when the _loadMore function is running
                if (_isLoadMoreRunning == true)
                  const Padding(
                    padding: EdgeInsets.only(top: 10, bottom: 40),
                    child: Center(
                      child: CircularProgressIndicator(),
                    ),
                  ),

                // When nothing else to load
                if (_hasNextPage == false)
                  Container(
                    padding: const EdgeInsets.only(top: 30, bottom: 40),
                    color: Colors.amber,
                    child: const Center(
                      child: Text('No more jobs'),
                    ),
                  ),
              ],
            ),
    );
  }
}

class NewsCardSkelton extends StatelessWidget {
  const NewsCardSkelton({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Skeleton(height: 120, width: 120),
        const SizedBox(width: defaultPadding),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Skeleton(width: 80),
              const SizedBox(height: defaultPadding / 2),
              const Skeleton(),
              const SizedBox(height: defaultPadding / 2),
              const Skeleton(),
              const SizedBox(height: defaultPadding / 2),
              Row(
                children: const [
                  Expanded(
                    child: Skeleton(),
                  ),
                  SizedBox(width: defaultPadding),
                  Expanded(
                    child: Skeleton(),
                  ),
                ],
              )
            ],
          ),
        )
      ],
    );
  }
}

Thank you.

CodePudding user response:

This code looks good to me!!. Maybe you should clear _posts in loadMore(). For example:

  // This function will be triggered whenver the user scroll
  // to near the bottom of the list view
  void _loadMore() async {
    if (_hasNextPage == true &&
        _isFirstLoadRunning == false &&
        _isLoadMoreRunning == false &&
        _controller.position.extentAfter < 300) {
      setState(() {
        _isLoadMoreRunning = true; // Display a progress indicator at the bottom
      });
      _page  = 1; // Increase _page by 1
      try {
        final res = await http.get(Uri.parse("$_baseUrl?$_page&$_limit"));

        final List fetchedPosts = json.decode(res.body);
        if (fetchedPosts.isNotEmpty) {
          if (!fetchedPosts.contains(fetchedPosts)) {
            
            setState(() {
              // added this line
              _posts.clear();

              _posts.addAll(fetchedPosts);
            });
          }
        } else {
          // This means there is no more data
          // and therefore, we will not send another GET request
          setState(() {
            _hasNextPage = false;
          });
        }
      } catch (err) {
        if (kDebugMode) {
          print('Something went wrong!');
        }
      }

      setState(() {
        _isLoadMoreRunning = false;
      });
    }
  }

CodePudding user response:

I can see your URL pattern look like trying to use GET URL parameters like this $_baseUrl?$_page&$_limit, I think it supposed to be something like $_baseUrl?page=$_page&limit=$_limit

  • Related