What I did with Knockout and I am Trying to do with Angular.
In my current project I have a table which data is being added by scroll event. When the user scrolls down I add 20 row to the end of the table and the total row count can reach 2k-10k. I start with showing 20 record and when the user scrolls down I keep adding 20 rows until reaching the total row count.
As in my Angular fiddle example when the repeat is used if a new data is pushed to the array ''Angular" executes all the records and render them again but knockout just executes and renders the new added record. In my project because I display thousands of data in a single table this way which angular works or I think that it works kills my performance.
It have been just a few week that I am using angular I don't know If I am doing anything wrong or if I need to modify some things.
Knockoutjs Example:
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Test</th>
</tr></thead>
<tbody data-bind="foreach: seats()">
<tr>
<td data-bind="text: mealName"></td>
<td data-bind="text: price"></td>
<td data-bind="text: $root.cellAdded()"></td>
</tr>
</tbody>
</table>
<button data-bind="click: $root.PushData()">I am Here</button>
JS:
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
self.cellAdded = function(){
console.log('Test Added');
return 'ok';
};
self.PushData = function(){
console.log('PushData Called');
self.seats.push({ mealName: "Standard (sandwich)", price: 0 });
};
// Editable data
self.seats = ko.observableArray([
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.95 },
{ mealName: "Ultimate (whole zebra)", price: 290 }
]);
}
ko.applyBindings(new ReservationsViewModel());
AngularJS Example:
<div ng-app>
<div ng-controller="TodoCtrl">
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Test</th>
</tr></thead>
<tbody >
<tr ng-repeat="seat in seats">
<td>{{seat.mealName}}</td>
<td>{{seat.price}}</td>
<td>{{callMe()}}</td>
</tr>
</tbody>
</table>
<button ng-click="addRow()">Add Row</button>
</div>
</div>
JS:
function TodoCtrl($scope) {
$scope.callMe = function(){
console.log('Test Added');
return 'Yes';
};
// initialize controller's model
$scope.seats = [
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.95 },
{ mealName: "Ultimate (whole zebra)", price: 290 }
];
// Define member functions
$scope.addRow = function() {
console.log('PushData Called');
$scope.seats.push( { mealName: "Standard (sandwich)", price: 0 });
};
}
I suggest updating to Angular 1.3+ and use its One time binding capability, given the records do not change after being added. This minimizes the watches on your DOM by a good amount and helps improving performance.
<div ng-app>
<div ng-controller="TodoCtrl">
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Test</th>
</tr></thead>
<tbody >
<tr ng-repeat="seat in seats">
<td>{{::seat.mealName}}</td>
<td>{{::seat.price}}</td>
<!--<td>{{callMe()}}</td>-->
</tr>
</tbody>
</table>
<button ng-click="addRow()">Add Row</button>
</div>
</div>
Also I recommend removing that function call in your expression because it's evaluated everytime Angular runs the digest cycle, which is a real performance killer.
If you want to check whether your model has updated, use $watch in your controller (https://docs.angularjs.org/api/ng/type/$rootScope.Scope).
$scope.$watch('seats', function() {
console.log('Test Added');
});
Another hint yet not related to performance: It's good practice and helps minimizing scope issues to always use a model object of some kind in your controllers. So your controller would look like this:
function TodoCtrl($scope) {
// initialize controller's model
$scope.model = {};
$scope.model.seats = [
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.95 },
{ mealName: "Ultimate (whole zebra)", price: 290 }
];
// Define member functions
$scope.addRow = function() {
console.log('PushData Called');
$scope.model.seats.push( { mealName: "Standard (sandwich)", price: 0 });
};
$scope.$watch('model.seats', function() {
console.log('Test Added');
});
}
and your HTML like this:
<div ng-app>
<div ng-controller="TodoCtrl">
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Test</th>
</tr></thead>
<tbody >
<tr ng-repeat="seat in model.seats">
<td>{{::seat.mealName}}</td>
<td>{{::seat.price}}</td>
<!--<td>{{callMe()}}</td>-->
</tr>
</tbody>
</table>
<button ng-click="addRow()">Add Row</button>
</div>
</div>
Also, as @Gabe already mentioned, ngInfiniteScroll might be a good addition for your use case: http://binarymuse.github.io/ngInfiniteScroll/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With