Collection-repeat continually calling function (HELP!)


#1

I have been banging my head against the wall for a while on this one, it may just be that I am doing something really stupid but I am looking for a bit of help fixing some behaviour in my app with collection-repeat.

In my html I have:

  <ion-item class="item item-avatar item-icon-right" collection-repeat="song in favorites" collection-item-width="'100%'" collection-item-height="'74px'" item-render-buffer="10" ng-click="playFavorites(favorites, $index)">
    <img ng-src="{{getCoverArt(song.coverArt)}}">
    <h2>{{ song.title }}</h2>
    <p>{{ song.artist }}</p>
  </ion-item>

getCoverArt() is a function in my controller which will take the ID of the song, hit a backend service to get either the path to the local cached copy of the image or the url to the image if there is no local copy.

getCoverArt works fine if I just pass an ID into it outside of collection repeat and returns and the image renders perfectly.

When I use it within the collection repeat like this I would expect it to call once for each item in the list, but what I find is that it calls continually and locks up the app.

Even with only 10 items in the list it just goes ballistic and I see 999+ calls in the console log almost instantly and the whole app becomes unresponsive.

Any help here would be greatly appreciated!


#2

you have to learn how collection repeat works:

it fills up you list with some empty entries to be smoother while scrolling.
take a look in the processed html-code and you will see it.

you can simply check:

<img ng-src="{{getCoverArt(song.coverArt)}}" ng-if="song.coverArt">

so for all empty entries the getCoverArt-function will not be executed


#3

Thanks for the pointer! I have implemented that through out my app and it has calmed it down quite a bit. Although I am also looking into other ways that i could inject the url into the object so it can just be called with {{song.imageSrc}} or something rather than calling a function as that seems neater but that means a lot of changes to the way I handle data on the client so it’s more of a long term thing to look into.


#4

How about using ng-repeat? You have a definitive behavior and it prevents these draw first behavior of collection-repeat


#5

for smaller lists I have used ng-repeat

but some of them are 1000+ items in a list and collection-repeat really does make a massive difference to scrolling performance.


#6

If your data comes from an own service --> loop there over each entry and put the paths directly on each object.

To improme a little bit performance --> add pager functionality to this service and use ion-infinite-scroll to implement something like lazy loading (increment page --> load next data)

So you have not to loop over all >1000 entries at once


#7

Thanks for the suggestions, I have made some progress on this. I have one odd behaviour that is currently stopping me though:

This is my code:

  <ion-item class="item item-avatar item-icon-right" collection-repeat="album in folders | filter:searchString.string" collection-item-width="'100%'" collection-item-height="'73px'" item-render-buffer="100" ng-href="#/app/browse/{{album.id}}">
    <img ng-src="{{imgURLs[album.id]}}" ng-init="getCoverArt(album.id)" ng-if="album.id">
    <h2>{{ album.name }}</h2>

    <ion-option-button class="button-dark"
        ng-click="cacheAlbum(album.id)"> cache
    </ion-option-button>

  </ion-item>

I have found some weird behaviour. the ng-init will only run for a certain number of items in the collection and the number of items is related to the value of item-render-buffer.

If I remove the item-render-buffer value from the above so that it is just at default (3 items according to docs), then the ng-init will run for the first 15 items in the collection and then never update again, the images for each item will just cycle through those first 15 images continually.

if I increase the item-render-buffer to 10 then the first 30 items are processed
if I increase the item-render-buffer to 100 then the first 300 items are processed

if I change to using ng-repeat then ng-init is called correctly for each item in the collection and everything works as it should, albeit slowly.

why does collection-repeat stop processing the the ng-init statements after a certain number of items? This seems like a bug to me.