AngularJS - A pagination demonstration incorporating intelligent logic inspired by Google's approach

I struggled to implement a paging solution that I came across online. The issue seems to be related to the timing of function calls, specifically how the setPage function is triggered before all data is retrieved, causing it to not properly determine the total number of items to display. Can someone review my code and see where I might be going wrong? Any help would be greatly appreciated.

Link to Paging Solution

function HistoryController($window, $scope, $modal, $state, toaster, PagerService, HistoryFactory, $timeout) {
    var vm = this;

    vm.uploads = [];
    vm.includeCancelled = false;
    vm.uploadDataModal = {};
    vm.pager = {};

    vm.setPage = setPage;

    activate();

    function activate() {
        getHistory();
        vm.setPage(1);
    }

    function setPage(page) {
        if (page < 1 || page > vm.pager.totalPages) {
            return;
        }

        // get pager object from service
        vm.pager = PagerService.GetPager(vm.uploads.length, page);

        // get current page of items
        vm.items = vm.uploads.slice(vm.pager.startIndex, vm.pager.endIndex + 1);
    }

    function getHistory() {
        HistoryFactory.getHistory(vm.includeCancelled).then(
            function(response) {
                _.each(response.data, function(upload) {
                    upload.inProgress = upload.status && ['INPROGRESS','NEW'].indexOf(upload.status.statusCd.trim()) > -1;
                });
                vm.uploads = response.data;

                if($state.params.reupload){
                    uploadProductionData();
                    $state.params.reupload = false;
                }
            });
    }

Snippet of HTML Code

<div class="chrthdr" ui-view="header"></div>
<div id="userResults">
<div class="card card-full-width">
    <div class="card-header dark-blue">
        <a class="card-config" data-toggle="uploadHistory" data-placement="left"><i class="glyphicon glyphicon-info-sign"></i></a>
        <div class="card-title">Data History</div>
    </div>
    <div class='form-horizontal range-date' style="overflow-y: auto;">
        <form>
            <div class="panel-body">
                <div>
                    <span class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px;  margin-right: 5px" type="button" ng-click="vm.uploadProductionData()">Upload Data</span>
                    <label>
                        <input type="checkbox" ng-model="vm.includeCancelled">Include removed executions
                    </label>
                </div>
                <div>
                    <table class="table">
                        <tr>
                            <th>Upload Date</th>
                            <th>Product</th>
                            <th>Comments</th>
                            <th>Template</th>
                            <th>Last Updated By</th>
                            <th>Last Updated</th>
                            <th>Status</th>
                            <th>Actions</th>
                        </tr>
                        <tr ng-repeat="upload in vm.uploads | orderBy:'uploadDate':true">
                            <td style="white-space: nowrap;">{{upload.uploadDate}}</td>
                            <td>{{upload.product}}</td>
                            <td style="white-space: nowrap;">{{upload.comments}}</td>
                            <td style="white-space: nowrap;">{{upload.templateName}}</td>
                            <td style="white-space: nowrap;">{{upload.lastUpdatedByUser}}</td>
                            <td style="white-space: nowrap;">{{upload.lastUpdateDate}}</td>
                            <td style="white-space: nowrap;">{{upload.status.statusName}}</td>
                            <td>
                                <button class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px; " ng-hide="upload.status.statusCd === 'NEW' || upload.status.statusCd === 'ERROR'" ng-click="vm.loadStagingPage(upload.dataLoadExecutionId, upload.product, upload.status)">View</button>
                                <span class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px; " type="button" ng-click="vm.cancelDataExecution(upload.dataLoadExecutionId)" ng-show="upload.inProgress || upload.status.statusCd === 'ERROR'">Remove</span>
                            </td>
                        </tr>
                    </table>
                </div>
                <div class="text-center">
                   <ul ng-if="vm.pager.pages.length" class="pagination">
                        <li ng-class="{disabled:vm.pager.currentPage === 1}">
                            <a ng-click="vm.setPage(1)">First</a>
                        </li>
                        <li ng-class="{disabled:vm.pager.currentPage === 1}">
                            <a ng-click="vm.setPage(vm.pager.currentPage - 1)">Previous</a>
                        </li>
                        <li ng-repeat="page in vm.pager.pages" ng-class="{active:vm.pager.currentPage === page}">
                            <a ng-click="vm.setPage(page)">{{page}}</a>
                        </li>               
                        <li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
                            <a ng-click="vm.setPage(vm.pager.currentPage + 1)">Next</a>
                        </li>
                        <li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
                            <a ng-click="vm.setPage(vm.pager.totalPages)">Last</a>
                        </li>
                    </ul>
                </div>
            </div>
        </form>
    </div>
</div>

Answer №1

One common error that many people make is not grasping the concept of asynchronous calls.

HistoryFactory.getHistory(vm.includeCancelled).then({})
is an asynchronous function, which means that it will initiate the call and then proceed to execute code after the async call without waiting for it to complete. The code inside .then({}) will only run after the async call has finished, which could take anywhere from 5 milliseconds to 5 seconds.

For example:

function activate() {
    getHistory();      // async call, does not pause execution
    vm.setPage(1);     // runs immediately after, even if data is not ready 
}

To address this issue, the code should be revised as follows:

function activate() {
    getHistory();
}

Additionally, update getHistory() to:

function getHistory() {
    HistoryFactory.getHistory(vm.includeCancelled).then(
        function(response) {
            _.each(response.data, function(upload) {
                upload.inProgress = upload.status && ['INPROGRESS','NEW'].indexOf(upload.status.statusCd.trim()) > -1;
            });
            vm.uploads = response.data;

            if($state.params.reupload){
                uploadProductionData();
                $state.params.reupload = false;
            }

            // Call setPage once data retrieval is complete
            vm.setPage(1);
        });
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Loading a Vuetify component dynamically within a Vue 3 environment

In my Vue 3 project, I am attempting to dynamically load Vuetify components using the code below: <template> <v-chip>try</v-chip> <component :is="object.tag">{{ object.content }}</component> </template> & ...

The object property is not being identified by the controller

Here is a snippet from my MLab-defined product document: { "_id": { "$oid": "596161e1734d1d25634366ce" }, "images": { "regular": [ "Amana Electric Range in Stainless Steel-1.jpg", "Amana Electric Range in Stainless Steel-2.jpg", "Ama ...

Enter a socket.IO chat room upon accessing an Express route

Encountering difficulty when attempting to connect to a socket.IO room while accessing a specific route in my Express application. The current setup is as follows: app.js var express = require('express'); var app = express(); var http = requir ...

Is there a way to redirect the user directly to the upload page without displaying the response?

Recently, I came across this code snippet that adds a progress bar to an upload form. Currently, the code displays the response from the upload page below the form. However, my goal is to redirect the user to the upload page so they can view the response t ...

Encountering an issue while attempting to retrieve information from Vuex store

I recently encountered an issue while trying to store my water data in Vuex. I followed the implementation below, but when I attempted to access my data array, it did not show up as expected. const store = new Vuex.Store({ state: { categories: ...

JavaScript Plugins for Cordova

The more I delve into the inner workings of Cordova, the clearer it becomes to me. Yet, one area that continues to perplex me is the structure of JavaScript plugins. Typically, I write my JavaScript code as follows, adhering to what I believe is the stand ...

PHP fails to retrieve data from a JavaScript Ajax function using the FormData object (specifically, when

I'm facing an issue where my file is not being detected when I send a FormData object using AJAX and PHP code. Both the `$_FILES` array and the `$_POST` array appear to be empty. However, the browser does send the file with the AJAX request. <inpu ...

Running an Express middleware function

While watching a tutorial on the Express framework, I came across some interesting code used by the instructor for handling requests. Here is how the route is set up: router.route('/').post(authController.restrictTo('admin', 'l ...

The Facebook messenger checkbox plugin does not appear to be displaying correctly

I have integrated the Facebook Messenger Checkbox Plugin into my AngularJS application by following the guide provided at this link. Initially, I was able to successfully display the messenger checkbox plugin on a page. However, upon navigating to another ...

Is there any re-rendering optimization feature in Angular 2?

After experimenting with React for a few months, I've noticed that it doesn't just re-render a component entirely. Instead, it identifies the differences and updates only those parts. Does Angular 2 operate in a similar manner? Additionally, whe ...

Having trouble retrieving a customized header from the HTTP response

I've encountered an issue with my Node.js server where I set a custom header. I added the Access-Control-Expose-Headers to allow access from browsers, and it works fine in Chrome and Firefox. However, I'm getting an error in PhantomJS saying "Ref ...

What is the process for making changes to a document in Mongoose?

My goal is to allow users to update existing mongoose documents using a form with method-override package. Despite trying various solutions found on Stackoverflow, I have not been able to resolve my issue. The desired functionality is for the user to view ...

Retrieve Data from Angular's ngRedux Store

Wanting to retrieve and react to changes in data from ngRedux-store, I am looking to utilize it in a guard with the CanActivate interface. In my previous method of fetching data, I typically used this code snippet: @select(['auth', 'IsAuth ...

What is the best way to define a variable within a function?

Here's a function designed to verify if the username has admin privileges: module.exports = { checkAdmin: function(username){ var _this = this; var admin = null; sql.execute(sql.format('SELECT * FROM tbl_admins'), (err, result, fields ...

Learn how to configure and utilize an AngularJS factory using ngResource along with passing parameters in the call

As a newcomer to Angular, I'm seeking guidance on creating a new factory utilizing ngResource instead of $http, with the ability to pass parameters. Following an example provided here, I have defined my factory as shown below: app.factory('abst ...

Can you explain the distinction between $translateChangeSuccess and $translateChangeStart and provide guidance on which one would be more suitable for my situation?

$rootScope.$on('$translateChangeSuccess', function () { A = $translate.instant('aaa'); B = $translate.instant('bbb'); C = $translate.instant('ccc'); }); Is there a difference between using $t ...

AngularJS flip card animation

Exploring the new AngularJS method for animations during page transitions, I am keen on integrating a card flip effect (resembling http://jsfiddle.net/nicooprat/GDdtS/) body { background: #ccc; } .flip { -webkit-perspective: 800; width: 400px; height: ...

Issue arising from the lack of direct communication between parent and child elements

I am facing an issue with indirect communication in a react native application. The situation involves a parent component, implemented as a class component, and a child component, which is a functional component. Here is the Parent component: constructor ...

Using JSON data to populate a select menu in AngularJS using the ng-options directive

UPDATE: I have successfully resolved my issue. Thanks for the assistance, everyone. I am working with an array of JSON objects that are structured like so: [{"id":"id1", "text":"text1"}, {"id":"id2", "text":"text2"},....] My goal is to populate an Angul ...

voting-app-powered-by-express-angular-node

Here are my two files for a simple voting app, but I'm facing an issue where the buttons are not increasing the count immediately. The counts only increase by one when the voting.html page is refreshed. Any assistance would be greatly appreciated. &l ...