Tips for enhancing the speed of ngRepeat when working with a large dataset in angular.js

I have a large dataset consisting of thousands of rows with about 10 fields each, totaling approximately 2MBs of data. My challenge is to effectively display this information in a web browser. The most obvious solution involves fetching the data, assigning it to $scope, and utilizing ng-repeat="" for rendering. However, this approach causes the browser to freeze for nearly thirty seconds as it inserts nodes into the DOM. How can I tackle this issue?

One potential strategy is to gradually add rows to $scope and allow ngRepeat to complete inserting one batch into the DOM before moving on to the next. Nevertheless, since ngRepeat does not provide feedback when it finishes "repeating", implementing this method may result in untidy coding.

Another option is to divide the data into pages on the server side and retrieve them through multiple requests, but this alternative introduces its own set of challenges.

In my search for a better solution, I scoured the Angular documentation for something akin to

ng-repeat="data in dataset" ng-repeat-steps="500"
, but came up empty-handed. As a newcomer to Angular practices, I acknowledge that I may be overlooking key insights. What are the recommended best practices in handling a situation like this?

Answer №1

@AndreM96 makes a valid point about optimizing user experience by displaying a limited number of rows at a time, which can be achieved through pagination or infinite scroll.

Implementing infinite scroll in Angular is straightforward using the limitTo filter. Simply set an initial limit and increment it when the user requests more data (typically done with a button).

<table>
    <tr ng-repeat="d in data | limitTo:totalDisplayed"><td>{{d}}</td></tr>
</table>
<button class="btn" ng-click="loadMore()">Load more</button>

//controller
$scope.totalDisplayed = 20;

$scope.loadMore = function () {
  $scope.totalDisplayed += 20;  
};

$scope.data = data;

Check out this JsBin for a live example.

However, keep in mind that excessive scrolling on mobile devices may cause lag, making pagination a better choice in those cases.

To implement pagination, you'll need the limitTo filter along with a custom filter to determine the starting point of displayed data.

Here's a JSBin showcasing a pagination setup.

Answer №2

One of the most effective strategies for handling large datasets is through the application of unique techniques such as Ionic's collectionRepeat directive and similar approaches. Referred to as 'occlusion culling', the concept revolves around displaying only the elements visible to the user, rather than a predetermined number like 50, 100, or 500. This results in improved scalability and performance.

Unlike traditional infinite scrolling methods which can lead to bloating and decreased scrolling efficiency, the collectionRepeat approach focuses on utilizing a limited set of elements that fit within the viewport and recycling them as needed. By dynamically refilling these elements with new data upon rotation out of view, this technique enables seamless information updates without the need for continuous creation and destruction cycles.

It's worth noting that while Ionic offers innovative solutions, the principles behind collectionRepeat can be adapted and implemented across various platforms due to its open-source nature. However, the functionality and creativity displayed by the Ionic team make their contributions highly valuable in this space.


A similar methodology can be observed in React, where elements outside the view are simply not rendered, resulting in impressive speed even when handling large datasets. Although some minor flickering may occur in basic implementations, the overall performance remains exceptional.


Lastly, implementing track by is strongly recommended for optimizing performance, even with smaller datasets. This practice can greatly enhance data management and processing efficiency.

Answer №3

If you're looking to optimize your AngularJS performance, check out this resource:

Improving AngularJS Speed: From 1200ms to 35ms

This article discusses a new directive that optimizes ng-repeat in four key ways:

Optimization#1: Cache DOM elements

Optimization#2: Aggregate watchers

Optimization#3: Defer element creation

Optimization#4: Bypass watchers for hidden elements

You can find the project on Github here:

How to Use:

1- Begin by including these files in your single-page app:

  • core.js
  • scalyr.js
  • slyEvaluate.js
  • slyRepeat.js

2- Add module dependency:

var app = angular.module("app", ['sly']);

3- Replace ng-repeat with sly-repeat

<tr sly-repeat="m in rows"> .....<tr>

Enjoy the optimized performance!

Answer №4

In addition to suggestions such as using track by and optimizing loops, I found another helpful tip.

<span ng-bind="::stock.name"></span>

This snippet of code will display the name once it has finished loading, and then stop monitoring it. Similarly, for ng-repeats, you can use:

<div ng-repeat="stock in ::ctrl.stocks">{{::stock.name}}</div>

Keep in mind that this technique is only compatible with AngularJS version 1.3 and above. From

Answer №5

One way to improve performance is by using the "track by" option:

<div ng-repeat="item in items track by item.id">

This is more efficient than:

<div ng-repeat="item in items">

source:https://www.example.com/article123

Answer №6

For websites where all rows are the same height, consider using the virtualizing ng-repeat feature:

Check out this interesting demo that also offers support for inertial scrolling.

Answer №7

Enhancing scrolling performance can be achieved through virtual scrolling, which is particularly useful for managing extensive lists and large datasets.

An effective way to utilize this technique is by incorporating Angular Material's md-virtual-repeat feature, as showcased in this Demo featuring 50,000 items.

This description from the virtual repeat documentation sums it up well:

Virtual repeat serves as a more efficient alternative to ng-repeat by only rendering enough DOM nodes to fill the container and recycling them as the user scrolls.

Answer №8

One golden rule: never keep the user waiting.

Keeping this in mind, a webpage that gradually loads over 10 seconds will feel faster than staring at a blank screen for 3 seconds before everything appears at once.

Instead of focusing on making the page fast from a technical standpoint, focus on making it appear fast to the user, even if it means the final result is slightly slower:

function applyItemlist(items){
    var item = items.shift();
    if(item){
        $timeout(function(){
            $scope.items.push(item);
            applyItemlist(items);
        }, 0); // <-- introducing a small delay of 10ms
    }
}

The code snippet above allows the list to grow gradually row by row, which may be slower than rendering everything at once. But from the user's perspective, it gives the illusion of speed.

Answer №9

A new approach suggested by @Steffomio

Rather than adding each item one by one, we can add items in chunks.

// Utilizing the chunks function obtained from:
// http://stackoverflow.com/questions/8495687/split-array-into-chunks#11764168
var chunks = chunk(folders, 100);

// Displaying the first set of items immediately
$scope.items = chunks[0];

var delay = 100;
angular.forEach(chunks, function(value, index) {
    delay += 100;

    // Skip the first chunk
    if( index > 0 ) {
        $timeout(function() {
            Array.prototype.push.apply($scope.items,value);
        }, delay);
    }       
});

Answer №10

At times, the data retrieval from the server happens in mere milliseconds (let's say around 100ms), but displaying that data on our web page takes significantly longer (approximately 900ms).

This means that a large portion of the time, about 800ms, is spent solely on rendering the web page itself.

To address this issue in my web application, I have implemented pagination or infinite scrolling to showcase a list of data. For instance, I display only 50 pieces of data per page initially, which requires just 50ms for loading.

As a result, the total time has been reduced from 900ms to 150ms. When a user requests the next page, the next set of 50 data points is displayed and so forth.

Implementing such a strategy can greatly enhance performance. Best of luck!

Answer №11

Implemented a custom directive (ng-repeat with lazy loading) 

This directive is designed to load data as the user scrolls to the bottom of the page, removing half of the previously loaded data each time. As the user scrolls back up to the top of the div, previous data (according to the page number) will be reloaded, once again removing half of the current data. This approach ensures that only a limited amount of data is present in the DOM at any given time, improving performance by avoiding rendering all data at once.

Here is the HTML code snippet:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
    <script data-require="<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="70111e17051c11025e1a0330415e435e08">[email protected]</a>" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="ListController">
  <div class="row customScroll" id="customTable" datafilter pagenumber="pageNumber" data="rowData" searchdata="searchdata" itemsPerPage="{{itemsPerPage}}"  totaldata="totalData"   selectedrow="onRowSelected(row,row.index)"  style="height:300px;overflow-y: auto;padding-top: 5px">

    <!--<div class="col-md-12 col-xs-12 col-sm-12 assign-list" ng-repeat="row in CRGC.rowData track by $index | orderBy:sortField:sortReverse | filter:searchFish">-->
    <div class="col-md-12 col-xs-12 col-sm-12 pdl0 assign-list" style="padding:10px" ng-repeat="row in rowData" ng-hide="row[CRGC.columns[0].id]=='' && row[CRGC.columns[1].id]==''">
        <!--col1-->

        <div ng-click ="onRowSelected(row,row.index)"> <span>{{row["sno"]}}</span> <span>{{row["id"]}}</span> <span>{{row["name"]}}</span></div>
      <!--   <div class="border_opacity"></div> -->
    </div>

</div>

  </body>

</html>

And here is the Angular code snippet:

var app = angular.module('plunker', []);
var x;
ListController.$inject = ['$scope', '$timeout', '$q', '$templateCache'];

function ListController($scope, $timeout, $q, $templateCache) {
  // Controller logic goes here
}

angular.module('plunker').controller('ListController', ListController).directive('datafilter', function($compile) {
  // Directive logic goes here
});

You can view a demo with the directive here.

If you are using UI-grid in your project, similar functionality exists with infinite-scroll feature.

Depending on the height of the division, new data is loaded as the user scrolls and previous data is removed. Here's an example of the HTML code:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.css" type="text/css" />
    <script data-require="<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fa9b949d8f969b88d49089bacbd4c9d482">[email protected]</a>" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.6/ui-grid.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="ListController">
    // Body content goes here
  </body>

</html>

And the corresponding Angular code:

// Angular code for UI Grid implementation goes here

You can check out a demo of UI Grid with infinite-scroll here.

Answer №12

If you have a large data set and multiple value drop down, it is recommended to utilize ng-options instead of ng-repeat.

ng-repeat can be slow because it iterates over all incoming values, whereas ng-options simply displays them in the select option.

ng-options='state.StateCode as state.StateName for state in States'>

This method is significantly faster than using:

<option ng-repeat="state in States" value="{{state.StateCode}}">
    {{state.StateName }}
</option>

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

Using jQuery to dynamically update the CSS of one table column depending on the attribute of another column

Welcome to my HTML table <!DOCTYPE html> <html> <body> <table> <thead> <th>Title1</th> <th>Title2</th> </thead> <tbody> <tr> <td><input type="checkbox" id=0 /></td> ...

Utilize ng-repeat to display a series of images, with the first image being placed within a unique div

My challenge lies in displaying product images using ng-repeat, where one image is located in a separate div. Let me share my code and explain what is happening. The API response provides product details and images [{"id_product":"1000","name":"Nikolaus ...

The issue lies with the event.target.name property - it appears to be inconsistent, working at times but failing to read properly at others

Whenever I attempt to click the button, I encounter an error. Interestingly, it seems to work on some occasions and fails on others. import React from 'react'; class Profile extends React.Component{ constructor(){ super(); th ...

Unable to access the contents of an array (React JS)

After fetching the content as an array and viewing its contents with console.log, I noticed that despite the array being populated, it has a length of 0, making it impossible to retrieve its elements using map. What could be causing this issue? https://i. ...

Leveraging data generated by a CasperJS script within an AngularJS application

After using yeoman.io to create an angular.js single page application, I found myself with app.js managing routes, mycontroller.js scripts, and an index.html file filled with "bower_components" references for libraries installed through the command line us ...

Tips for using the deferred method in ajax to enhance the efficiency of data loading from a php script

I recently discovered this method of fetching data simultaneously using ajax. However, I'm struggling to grasp the concept. Can someone please explain how to retrieve this data from a PHP script and then add it to a div similar to the example provided ...

Error message in Leaflet JS: Unable to access property 'addLayer' because it is undefined when trying to display drawnItems on the Map

My attempt to showcase a Leaflet Map with polygon-shaped surfaces encountered an issue. Sometimes, I face the error "cannot read property 'addLayer' of undefined," but when the page is refreshed, the map renders correctly. I am unsure where I wen ...

Utilizing Restangular to capture and manipulate error messages

I'm currently working on implementing an interceptor for all requests. I have decided to utilize [addResponseInterceptor][1] in restangular. The documentation states: The responseInterceptor is called after each response is received from the serve ...

Utilizing .env Variables in NestJS Main App Module for Establishing Database Connection

I recently embarked on my first NestJS project, where I initially had a hardcoded database connection string in app.module.ts that worked perfectly fine. However, our project requirements called for fetching the database configuration values from environm ...

Using Regular Expressions in Firebase Functions to achieve a 'Clean Path' when utilizing app.use() in Express.js

Objective: I want Express to return /register when the browser URL is http://localhost:5000/register. This seemingly simple goal is proving to be a challenge with Express. Let's start by looking at my firebase.json: firebase.json: "hosting": { ...

How can I adjust the vertical position of Material-UI Popper element using the popper.js library?

https://i.stack.imgur.com/ZUYa4.png Utilizing a material-ui (v 4.9.5) Popper for a pop-out menu similar to the one shown above has been my recent project. The anchorElement is set as the chosen ListItem on the left side. My goal is to have the Popper alig ...

Showing JSON information on a web browser

Here is a snippet of JSON data that I am working with: {"earthquakes":[{"datetime":"2011-03-11 04:46:23","depth":24.39999999999999857891452847979962825775146484375,"lng":142.36899999999999977262632455676794 ...

Using regular expressions to eliminate the width attribute from tables

Currently, I am carrying out some HTML processing before storing the data in the database. If a user pastes content containing HTML tables, I need to eliminate certain tags and attributes. To extract the table content, I am using content.match('<t ...

Updating Firebase without altering the syntax can be achieved by following specific steps to

I'm feeling a bit lost on how to tackle this, as the project I've been handling is currently using firebase 7.14.0. Being a new developer, I've been struggling with this version due to the lack of documentation available. Is there a way for ...

The color type input is not responding to the onChange event

I have been searching a lot and exploring answers on Stack Overflow, yet I have had no luck. I am trying to retrieve the color value when the color is changed in an input field. Here is the code I am using, could you please assist me in finding out why it ...

Using AngularJS to display a targeted row in a table

I am currently working with a basic table and using ng-repeat to display rows in the table. I have a specific requirement where I want to show an additional row when a regular row is clicked. This additional row should contain custom markup in just one co ...

Tips for transferring data between two forms in separate iFrames

I'm trying to achieve a functionality where the data entered in one form can be submitted to another form within an iframe. The idea is to allow visitors to preview their selected car in the iframe, and if satisfied, simply press save on the first for ...

IE7 is failing to execute jQuery and Javascript code

The code snippet below is encountering compatibility issues with IE7, despite functioning properly on IE 8, IE 9, and all other browsers. Even the inclusion of alert("something"); does not yield the desired outcome - curiously, another script is executing ...

What could be the reason for v-model not functioning properly within vue.extend?

I've configured a page structure similar to the following: <main id="app"> <div id="mount-place"></div> </main> <script type="text/x-template" id="my-template"> ...some code her ...

What steps can be taken to resolve the issue of receiving the error message "Invalid 'code' in request" from Discord OAuth2?

I'm in the process of developing an authentication application, but I keep encountering the error message Invalid "code" in request when attempting to obtain a refresh token from the code provided by Discord. Below is a snippet of my reques ...