Reputation: 475
I have a bunch of angular filters which I am using to sort out my data, however, my app seems to load pretty slowly. I am wondering if there is a better way for me to structure my code in order to improve performance.
js
var myApplication = angular.module('myApp', ['ngColorThis']);
myApplication.controller("Catalog", function ($scope) {
$scope.books = books;
$scope.showInfo = false;
})
.filter('mydate', function() {
return function(input) {
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1; //January is 0, so always add + 1
var yyyy = today.getFullYear();
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
today = mm + '/' + dd;
return (input == today)
}
})
.filter('past', function() {
return function(input) {
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1; //January is 0, so always add + 1
var yyyy = today.getFullYear();
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
today = mm + '/' + dd;
return (input)
}
})
.filter('January', function() {
return function(input) {
return input.slice(0,2) === '01';
}
})
.filter('February', function() {
return function(input) {
return input.slice(0,2) === '02';
}
})
.filter('March', function() {
return function(input) {
return input.slice(0,2) === '03';
}
})
.filter('April', function() {
return function(input) {
return input.slice(0,2) === '04';
}
})
.filter('May', function() {
return function(input) {
return input.slice(0,2) === '05';
}
})
.filter('June', function() {
return function(input) {
return input.slice(0,2) === '06';
}
})
.filter('July', function() {
return function(input) {
return input.slice(0,2) === '07';
}
})
.filter('August', function() {
return function(input) {
return input.slice(0,2) === '08';
}
})
.filter('September', function() {
return function(input) {
return input.slice(0,2) === '09';
}
})
.filter('October', function() {
return function(input) {
return input.slice(0,2) === '10';
}
})
.filter('November', function() {
return function(input) {
return input.slice(0,2) === '11';
}
})
.filter('December', function() {
return function(input) {
return input.slice(0,2) === '12';
}
});
html
<ul>
<li class="pane1">
<div class="bg" ng-repeat="book in books" >
<div ng-show=" book.doc.date | mydate" >
<div class="date">{{book.doc.date}}</div>
<div class="title">{{book.doc.title}}</div>
<div class="quote">{{book.doc.quote}}</div>
<div class="attribution">-{{book.doc.attribution}}</div>
<div class="textt">{{book.doc.text}}</div>
<div style="height:10px"></div>
</div>
</div>
</li>
<li class="pane2">
<div class="january" ng-click="showJan = !showJan">
<div class="titletext">January</div>
</div>
<div class="bg" ng-repeat="book in books ">
<div ng-show="showJan">
<div style="padding-top:10px; border-bottom:2px solid #ededed;" ng-click="showInfo = !showInfo" ng-show=" book.doc.date |January">
<div id="circleJan"><div class="day">{{book.doc.day}}</div></div>
<div class="title">{{book.doc.title}}</div>
<div class="quote" ng-show="showInfo">{{book.doc.quote}} </div>
<div class="attribution" ng-show="showInfo">-{{book.doc.attribution}}</div>
<div class="textt" ng-show="showInfo">{{book.doc.text}}</div>
<div style="height:10px"></div>
</div>
</div>
</div>
<div class="february" ng-click="showFeb = !showFeb">
<div class="titletext">February</div>
</div>
<div class="bg" ng-repeat="book in books ">
<div ng-show="showFeb">
<div style="padding-top:10px; border-bottom:2px solid #ededed;" ng-click="showInfo = !showInfo" ng-show=" book.doc.date |February">
<div id="circleFeb"><div class="day">{{book.doc.day}}</div></div>
<div class="title">{{book.doc.title}}</div>
<div class="quote" ng-show="showInfo">{{book.doc.quote}}</div>
<div class="attribution" ng-show="showInfo">-{{book.doc.attribution}}</div>
<div class="textt" ng-show="showInfo">{{book.doc.text}}</div>
<div style="height:10px"></div>
</div>
</div>
</div>
<div class="march" ng-click="showMarch = !showMarch">
<div class="titletext">March</div>
</div>
<div class="bg" ng-repeat="book in books ">
<div ng-show="showMarch">
<div style="padding-top:10px; border-bottom:2px solid #ededed;" ng-click="showInfo = !showInfo" ng-show=" book.doc.date |March">
<div id="circleMarch"><div class="day">{{book.doc.day}}</div></div>
<div class="title">{{book.doc.title}}</div>
<div class="quote" ng-show="showInfo">{{book.doc.quote}}</div>
<div class="attribution" ng-show="showInfo">-{{book.doc.attribution}}</div>
<div class="textt" ng-show="showInfo">{{book.doc.text}}</div>
<div style="height:10px"></div>
</div>
</div>
</div>
Upvotes: 1
Views: 445
Reputation: 17579
There are whole bunch of issues with your code in terms of performance best practices.
Always use track by
part of ng-repeat
. That the first thing to do when you have performance issue
Avoid filters all together on big lists. Create another property that will hold filtered array.
Turn off debug information ($compileProvider.debugInfoEnabled(false);
).
Use ng-if
rather than ng-show
and ng-hide
as they actually remove nodes from DOM with corresponding bindings
@JDTLH9 already mentioned one-time-bindings. Use them when appropriate
And something unrelated to angular - always try to think of proper data structures for the problem you are solving. If you have a list of months and you have list of books that you need to spread across values in first array, you can create a hash map (simple object in js) with keys to be month name or code and value be filtered array. This way you are not travesting your array 12 times. See @cubbuk answer for an easy way of doing that with underscore/lodash.
Another thing you might want to consider with your example is pre-populating month value for each book, once you've got it from server. This way you can have one ng-repeat
with simple filter:
<div ng-repeat='book in books track by book.id | month: selectedMonth' >
...
And tab buttons just changing value of $scope.selectedMonth
UPDATE: there is also cool library that helps operating big arrays of data that you want slice and dice in memory: http://square.github.io/crossfilter/
There is also module for angular: https://github.com/Wildhoney/ngCrossfilter
But the thing is, unless you actually have several hundreds thousands records in your array, you should not have any issue with just fixing issues mentioned above. However, should you find yourself in need of searching in huge arrays (100k+ items) you really need to use advanced in memory indexes, and crossfilter is a huge help.
Upvotes: 1
Reputation: 1775
If using 'angularjs' 1.3 or higher, try the single-bind functionality for a significant performance boost on your read-only 'ng-repeat's.
Read about this here
Change you code to use a double colon before the array:
<div class="bg" ng-repeat="book in ::books ">
Upvotes: 0
Reputation: 7920
You can use already existing date filter of AngularJS if you need date formatting. Other than as far as I see you are trying to split your records into months. Instead of using filters in this case grouping your data by months in your controller would be easier. So each group would contain records of a specific month and you can list these arrays in your view rather than creating filters for each month. Here is a script for grouping your records by month using libraries underscore
and moment
$scope.booksPerMonth = _.group($scope.books, function(book){
return moment(book.doc.date).month();
});
//$scope.booksPerMonth[0] contain books of January you can use ng-repeat to traverse months, then another ng-repeat to traverse books of the month.
Upvotes: 0