dmgig
dmgig

Reputation: 4568

AngularJS: Remove $watch from ng-repeat

I've built a report which uses a set of nested ng-repeat directives to create what can be an enormous table. It works well to build the table, but after that, the scrolling performance is affected greatly - I assume this is due to what must be the large number of watches created by the ng-repeats.

The report only has to be built once and then is static. I don't need to watch the data continually.

I have two questions:

A) is there anyway to see a list of all the variables Angular is currently watching?

EDIT: This post was a great help in learning how to benchmark

B) Is there anyway to tell Angular to stop all of the watches it is doing? I've seen lots of posts about canceling watches which one sets up oneself, but that these are native directives, I'm not sure how I'd tap into them.

My preference would be to have a variable that I can say "if truthy, then do all watches, if not, then do not watch" or a function to just say "start watches" and "stop watches".

I have set up a very nice DOM watching service which can tell when all of the ng-repeats have executed, so I can know when I want to stop watching.

This is the table itself. Aside from tk-ng-repeat-completed, the other "tk-" attributes are just used for data and aren't actually directives.

<div class="table-responsive">

    <table tk-sticky-column id="records" class="table table-striped table-hover table-condensed">

        <!-- tbody[n] -->
        <tbody class="dataset" ng-repeat="dataset in report.data track by $index" tk-ng-repeat-completed>
            <!-- row[0] -->
            <tr class="headline">
                <!-- header[0] label -->
                <th class="headline" style="background-color:#042E34;">
                    <div style="width:200px;"><h4>{{report.labels.y[$index]}}</h4></div>
                </th>
                <!-- header[n] label -->
                <th ng-repeat="x_label in report.labels.x" tk-ng-repeat-completed
                    class="datapoint date"
                    tk-raw-data="{{x_label}}">
                    <em><small>{{x_label}}</small></em></th>
                <!-- header[last] space for addition @todo remove this, add during calculations -->
                <th class="date"></th>  
            </tr>
            <!-- row[n] -->
            <tr ng-repeat="(key, datapoints) in dataset" tk-metric-key="{{key}}">
                <!-- column[0] label -->
                <td tk-metric-key="{{key}}" 
                    tk-calc="{{report.labels.data[key].calc}}"
                    class="rowdesc begin">{{key}}</td>
                <!-- column[n] data -->
                <td ng-repeat="datapoint in datapoints track by $index" tk-ng-repeat-completed
                    ypos="{{$parent.$parent.$parent.$index}}" xpos="{{$index}}" tk-metric-key="{{key}}"
                    class="datapoint"
                    tk-raw-data="{{datapoint}}">
                        {{datapoint}}</td>
            </tr>

        </tbody>

    </table>

</div>

Upvotes: 8

Views: 4546

Answers (1)

wesww
wesww

Reputation: 2873

I'd recommend checking out the single-bind syntax they introduced in 1.3, if you're on a version greater than or equal to that one. It works really well and is very simple to implement. Here's an example:

normal syntax, which creates a watcher for each variable:

<div ng-repeat="foo in vm.bar">
  {{foo}}
</div>

single-bind syntax, with no watcher on the nested variable inside the repeat:

<div ng-repeat="foo in vm.bar">
  {{::foo}}
</div>

edit:

I forgot to mention that if your data isn't going to change at all after it gets populated the first time (e.g. from a $http.get), you can also just use the single-bind syntax on the top level ng-repeat:

<div ng-repeat="foo in ::vm.bar">
  {{::foo}}
</div>

Upvotes: 25

Related Questions