0

I have a ng-repeat with multiple ng-show condition inside. Something like this (fictive example):

<ul>
  <li ng-repeat="item in items | filter:searchFilter" >
    <label ng-show="item.label==1">{{item.label}}</label>
    <label ng-show="item.label==2">{{item.label}}</label>
    <label ng-show="item.label==3">{{item.label}}</label>
    <label ng-show="item.label==4">{{item.label}}</label>
    <label ng-show="item.label==5">{{item.label}}</label>
    <label ng-show="item.label==1">{{item.label}}</label>
    <label ng-show="item.label==2">{{item.label}}</label>
    <label ng-show="item.label==1">{{item.label}}</label>
  </li>
</ul>

I am using ng-show for formatting purpose, e.g. :

I want to show the cellphone column, when the item.cellphone is not empty...

I have a big data source (+1000 rows) and I have noticed performance problem when I use the filter.

If I remove most of the ng-show conditions, the performance is good. Here's live example :

  1. Ng-show performance problem
  2. Without ng-show

I know you can improve the performance with a "track by" (here's an topic about it), but it look like it is not enough to make the filter "smooth" (at least, not too laggy).

Is there a way to improve the filter performance of ng-repeat with multiple ng-show condition and a large data source ?

Community
  • 1
  • 1
Vinc 웃
  • 1,187
  • 4
  • 25
  • 64
  • 1
    You have way too many rows and watches. Some posts about Angular performance say you shouldn't have more than 2000 watches. In your example you have at least 4500 * 7! You need paging or the like. – hgoebl Jan 13 '15 at 21:31

1 Answers1

3

Performance tuning really depends on some of the constraints that you're facing. Here are a few suggestions:

1) Do you really need to show/hide the labels, or will not creating them at all suffice? If they don't need to exist, use ng-if instead of ng-show. This will reduce the number of watchers as well as the number of DOM elements in your example drastically.

2) If you can use Angular 1.3+ and can assume the labels are static ids, use one-time binding to avoid having so many watchers {{::label}}

Modifying your example with these suggestions results in: http://jsbin.com/madefuqami/2/edit

Ultimately, however, if you keep adding elements then at some point your app will become slow. Angular's dirty-checker will look at each of these ng-show (or ng-if) and {{}} bindings on every $digest cycle. Plus the DOM will get unnecessarily large - there's a good chance that you don't need the browser to do all of the work associated with maintaining HTML and styling for element 3000 when only 1-50 fit on your screen.

A more robust solution would involve looking into pagination or virtualization. This can either be done server-side, or in Javascript.

I suggest server-side pagination. Ultimately, it will scale better and make for a cleaner solution. However, if you decide to go the Javascript virtualization route, there are libraries available already such as angular-virtual-scroll

DRobinson
  • 4,441
  • 22
  • 31
  • 1) `ng-if` produces the same count of watches as `ng-show` – hgoebl Jan 13 '15 at 21:28
  • No it doesn't. Any watchers nested inside the `if` are saved. `
    {{someProperty}}
    ` does not have to watch `{{someProperty}}`. In this case this is up to 8 instances of `{{item.label}}`
    – DRobinson Jan 13 '15 at 21:29
  • You're right. With ng-if the watchers for {{...}} can be saved. But still the `ng-if` has to be watched and in his case there are 4500*7 (or 8 in SO example). – hgoebl Jan 13 '15 at 21:34
  • Hence my suggestion that he'll eventually have to go with pagination or virtualization (the whole bottom half of my answer). But until then, using `ng-if` is significantly better than `ng-show`, unless the element is required for some reason such as animation, and I believe that's something that's worth being aware of. – DRobinson Jan 13 '15 at 21:35
  • Absolutely right. Maybe a `ng-switch` could save more watches (in case ng-if conditions are mutually exclusive - the example seems to be a bit derived). – hgoebl Jan 13 '15 at 21:38