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

Is the treatment of __proto__ different in the fetch API compared to manual assignment?

When using fetch to retrieve a payload containing a __proto__, it seems that the Object prototype is not affected in the same way as when directly assigning to an object. This behavior is beneficial as it ensures that the Object prototype remains unaffect ...

JavaScript class with callback function commonly used

I am looking to create a JavaScript class that can register multiple functions to run with a common callback. Each registered function should run asynchronously, and once they have all completed, the specified callback function should be executed. In addi ...

Using Material-UI to implement a Link component from the react-router library

I'm having trouble integrating the <Link/> component into my material-ui AppBar. Here is my navigation class: class Navigation extends Component { constructor(props) { super(props) } render() { var styles = { appBar: { ...

Achieve a new line break when the user hits the "Enter" key using HTML and JavaScript

I'm in the process of developing a Chrome Extension that allows users to create a to-do list. My goal is to enable users to submit their task by pressing the "Enter" key, which should move the task to the next line after submission. I am currently fac ...

Clicking on a table will toggle the checkboxes

I am facing an issue with this function that needs to work only after the page has finished loading. The problem arises due to a missing semicolon on the true line. Another requirement is that when the checkbox toggle-all is clicked as "checked", I want ...

Send a hidden field value with AngularJS and retrieve it using PHP

Hello, I am having trouble posting a hidden value in my PHP code. I have included both my HTML with Angular and PHP code below. When I check the result in ajax_function.php page, I am only able to retrieve the text box value and not the hidden field value. ...

Formatting numbers in JavaScript objects

I am looking to iterate through an array of objects and convert the string values into numbers. Here is a sample scenario: I have data in a format similar to the variable provided below. When passing this array to a kendo chart, it seems to have trouble r ...

methods for transferring global variable from view to controller in angularjs

Currently, I am facing an issue with sending backend data from EJS to the frontend controller of AngularJS. app.js I am passing data to view/indexcontents. var users = [ { name: 'john', email: '<a href="/cdn-cgi/l/email-pro ...

Creating visuals from written content

I am attempting to transform Y[0] into an image rather than text. Currently, it is only displayed as a plain text link and not as an image. <html> <head> <script type="text/javascript"> function modifyContent(){ var rows=document.g ...

Applying CSS styles to a page depending on certain conditions

Currently, I have a page in SharePoint that can function as a pop-up. I am using JavaScript to identify whether it is a pop-up by checking if window.location.search.match("[?&]IsDlg=1"). However, I am struggling to figure out how to insert CSS based on ...

Troubleshooting issue: JSON object is returning undefined despite its presence in NASA API integration with ReactJS

{this.imageRenderer(item.data[0].media_type, item.links[1], item.links[0])} When trying to access item.links, it shows as undefined even though it is present. (Data is retrieved from NASA API) Image: As seen above, the links attribute exists. I am puzzle ...

Having trouble with logging in/out, registration, and my submitPost function has suddenly ceased to work

Grunt is not showing any errors and when using the debugger "Error: [$injector:unpr] Unknown provider: AuthProvider <- Auth <- user <- NavCtrl also "Error: [$injector:unpr] Unknown provider: AuthProvider <- Auth <- user You can find the ...

How can I interact with a v-dialog component within a child component in Vue.js using Vuetify?

Exploring Vue.js for the first time and hoping to display a login dialog upon button click. To maintain cleanliness in my code, I shifted the dialog to a child component within a parent component with nested LoginDialog. Below are snippets of the parent co ...

Creating an animated transition for an element's height with CSS

I need to animate the height of a div that doesn't have a specified height. Using max-height isn't an option due to multiple potential height amounts. I attempted adding transition: height 0.2s ease to the div, but it didn't work as expecte ...

Remove a div element with Javascript when a button is clicked

I am working on a project where I need to dynamically add and remove divs from a webpage. These divs contain inner divs, and while the functionality to add new divs is working fine for me, I'm facing some issues with removing them. The code snippet b ...

What is the proper way to annotate a controller so that it functions correctly when minified, especially when it relies on a combination of objects from Angular and a resolve method?

I'm facing an issue with wiring up the modalController properly to Angular's DI container. My angular view looks like this: <div ng-controller="myController"> {{helloWorld}} <br /><br /> <button type='button ...

Evaluating the functionality of Express Js Server with mocha and chai

I'm currently struggling to properly close the server connection in my Express server when testing it with Mocha and Chai. It seems that even after the test is completed, the server connection remains open and hangs. Index.js const express = require( ...

Executing a function by clicking on an element with the `ng-click` directive within a Bootstrap modal

I'm working on an app that allows users to submit posts for review. When a user clicks the add post button, I have a Bootstrap modal pop up to confirm their choice. Within this modal, there is a "confirm" button that should trigger a function. Strang ...

There was a SyntaxError that caught me by surprise in my Javascript code when it unexpectedly encountered

I have been encountering an error in my code consistently, and I am struggling to comprehend why this is happening. The problematic area seems to be in line 29 of my Javascript file. HTML <link href="Styles12.css"; type="text/css" rel="stylesheet"> ...

Uncovering the secrets to fetching numerous JSON files asynchronously using JavaScript and JQuery

My goal is to fetch multiple JSON files using JavaScript or jQuery and extract elements named j_name, j_value, and j_sts into sarr[i], rarr[i], and parr[i], respectively. var sarr = new Object; var rarr = new Object; var parr = new Object; //num_json rep ...