5

Let's suppose a list of 1000 items displayed with infinite scrolling.

Each item displays: a person's firstName, lastName, and mood. (to make it simple)

Initially, I didn't want to listen for updates.
So the great angular-bindonce directive or even better: angular 1.3 one-binding feature made the trick.

Now, I created a pull-to-refresh component, allowing to refresh the whole items.
However, as binding once, (and not reloading the page) my whole list didn't take the updates in account.

Using angular-bindonce, I have this currently:

<div bindonce ng-repeat="person in persons track by person.id">
  <span bo-text="person.firstName"></span>
  <span bo-text="person.lastName"></span>
  <span bo-text="person.currentMood"></span>
</div>

The pull-to-refresh triggers this function:

$scope.refresh() {
    Persons.getList(function(response)) {
      $scope.persons = response.data;  //data being an array
    }
}

Question is:

Is there a way to refresh all the data ONLY when the pull-to-refresh is triggered?
In this case, I would be able to keep this one-binding that would greatly improve performance when dealing with huge lists of persons.

Until now, I'm forced to....use two-way binding, the natural way of Angular works.

More generally, how to deal with huge lists with infinite scrolling that needs to be updated only when some events are triggered?

Mik378
  • 21,881
  • 15
  • 82
  • 180
  • http://blog.thoughtram.io/angularjs/2014/10/19/exploring-angular-1.3-ng-model-options.html interesting... – Mik378 Dec 04 '14 at 20:09
  • 1
    do you need to track by person.id? if you remove the track by, normal bind once {::} syntax works fine- – chrismarx Apr 22 '16 at 14:26
  • 1
    Like @chrismarx suggested, changing from track by $index to track by my own unique id seems to work – Ladmerc Aug 23 '16 at 05:44
  • 1
    @Ladmerc You may like : http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/ – Mik378 Aug 23 '16 at 06:15

3 Answers3

3

Get angular-bind-notifier.

Use native bindings (with a somewhat modified syntax) and setup your markup like so:

<div ng-repeat="person in persons track by person.id" bind-notifier="{ eventKey:watchedExpression }">
  <span>{{:eventKey:person.firstName}}</span>
  <span>{{:eventKey:person.lastName}}</span>
  <!-- or with ng-bind if you prefer that -->
  <span ng-bind=":eventKey:person.currentMood"></span>
</div>

Now, whenever the value of watchedExpression changes - a $broadcast will be sent down through the childscope created by bind-notifier and tell every binding with the :key:expr syntax to re-evaluate.


If you need to, you can also send the $broadcast manually in the following format:

$scope.$broadcast('$$rebind::' + key) // where 'key' === 'eventKey' in the example above.
0

refresh-on directive could do the trick, found a reference HERE:

<div bindonce="persons" refresh-on="'refresh'" ng-repeat="person in persons track by person.id">
  <span bo-text="person.firstName"></span>
  <span bo-text="person.lastName"></span>
  <span bo-text="person.currentMood"></span>
</div>
Community
  • 1
  • 1
ale
  • 10,012
  • 5
  • 40
  • 49
  • `refresh-on` seems not native to bindonce directive. – Mik378 Dec 04 '14 at 18:05
  • you need the latest version of bindonce – Pedro Justo Dec 04 '14 at 18:07
  • It's weird. The version in the github branch: rebind-debug has the directive. It's 0.3.1. The master is 0.3.2 and doesn't have it. I'm using the master currently. – Mik378 Dec 04 '14 at 18:09
  • I found this: https://medium.com/@kentcdodds/angularjs-one-time-bindings-and-recompiling-templates-9857b2cead01 – Mik378 Dec 04 '14 at 18:12
  • You hare right the directive used in my linked answer is related to https://github.com/Pasvaz/bindonce – ale Dec 04 '14 at 18:14
  • But if you search for "refres..." you wouldn't find any matches in the "master" version. – Mik378 Dec 04 '14 at 18:18
  • Here you can read the entire story, I am sorry that I can't help you more ... https://github.com/Pasvaz/bindonce/issues/42 – ale Dec 04 '14 at 18:34
0

Instead of trying to work around not using two-way binding but still have all of its benefits there is more likely and easier solution. You say that there are 1,000 rows, are all 1,000 rows with the viewport / visible to the user at once?

I would assume not, so I would suggest using a buffered view for the list of items. Buffering the rows would mean that the rows that are not visible have no bindings but still take up space in the DOM so the scroll bar is always accurate.

The one major caveat of buffering is that all rows should be the same height, no variable height rows.

Here are some virtual scrolling / buffering directives to take a look at:

https://github.com/EnzeyNet/VirtualScroll

https://github.com/stackfull/angular-virtual-scroll

https://github.com/kamilkp/angular-vs-repeat

Enzey
  • 5,254
  • 1
  • 18
  • 20
  • My rows haven't got the same height. – Mik378 Dec 04 '14 at 18:38
  • Have you considered a static height? Using the virtual scrolling directives will make your app's performance scale better with a lot of data and make the binding a non-issue. – Enzey Dec 04 '14 at 18:42
  • Some items should show much more info than others. I've tried collection-repeat of ionic framework too. – Mik378 Dec 04 '14 at 18:43