22

I'm building an hybrid app using ionic and AngularJS (AngularJS-material). This app also has an integrated chat built with Node.js and socket.io.

I have the problem now that with only 200 messages the app gets very slow to load all the messages (200ms in Browser -> 4sec in app, even with CrossWalk, and with track by message.id) and also typing in the the textarea to insert the message is slowed down.

I have two solutions to resolve this:

  1. Virtual Repeat (md-virtual-repeat)
  2. Infinite Scroll (ion-infinite-scroll)

1) I think that virtual repeat would be the best solution (I have already implemented it on another page and it scrolls 1500 items like a charm) but the problem is that the messages can have different heights based on their lenghts and md-virtual-repeat requirements are that all the elements must have the same height to work.

2) So maybe we can pivot to the Infinite Scroll method but the problem now is that doing it with the ion-infinite-scroll directive gets a bit tricky since a chat needs to trigger the loadMore() when reaching the top and not the bottom.

So my question is: Does anybody have a workaround to have a smooth/fast ng-repeat inside a chat using or a virtual-repeat directive that can handle different heights or an infinite scroll that works at the top ?

Matteo Cardellini
  • 876
  • 2
  • 17
  • 41

6 Answers6

2

Couple of things you could try to speed it up.

One would be to use something like quick-ng-repeat: https://github.com/allaud/quick-ng-repeat instead of built in angular js ng-repeat

Another would be to use one time binding where ever possible to prevent angular from constantly looking for changes during every digest cycle: https://docs.angularjs.org/guide/expression#one-time-binding

And of course, if it's possible, try using chrome's developer tool profile option to find out which of the functions are slowing the application down ; )

PS: Might be worth checking out this thread to see how reverse infinite scrolling could be implemented: Implementing a reverse infinite scroll using ngInfiniteScroll directive in AngularJS

Community
  • 1
  • 1
Chanthu
  • 1,794
  • 1
  • 15
  • 22
2

Efficient scroll lists like md-virtual-repeat or collection-repeat need to know the height of each item in order to work. That’s because they need to know the scroll position, e.g. to show a scrollbar or to be able to skip frames for quick swipe-down motions. The scroll position itself can only be found if you know both how much has been scrolled (we need the height of elements above) and how much there is left to scroll (we need the height of elements below).

What you can do is use a factory to compute the height of each element before injecting them into the loop. This can be done by creating a container with the same properties as the target container (e.g. CSS classes), appending the newly-loaded elements, compute their height (using element.offsetHeight), and removing the container after.

Be aware that this is quite heavy and will likely cause a small lag spike.

Iso
  • 3,148
  • 23
  • 31
  • Yeah I also tought about that but, since i don't have any slowness' problems on the page (since i used track by id) but it only takes a lot of time to just render the messages the first time, do you think this method will actually be an improvement ? – Matteo Cardellini Jan 04 '16 at 22:11
  • It's definitely an improvement over `ng-repeat` if you load like < 30 items (messages) at a time and your list is growing steady! – Iso Jan 05 '16 at 13:00
  • @Iso have you implemented this approach before or have you read about anyone exemplifying how they have done it? – pelican_george Jan 20 '17 at 12:14
1

Have you taken a look at React.js as a solution? It uses a virtual DOM which makes updating long lists more efficient.

There is an open-source repo on GitHub that mixes Angular and React, called ngReact.

overview: http://ngreact.github.io/ngReact/

docs: http://ngreact.github.io/ngReact/docs/ngReact.html

repo: https://github.com/ngReact/ngReact

Hope this helps.

Matt
  • 33,328
  • 25
  • 83
  • 97
  • I personally don't know React and never used it. If this would reveal being the best solution how much time do you think would be required to learn it ? I'm a freelancer and i need to run against the time to make a living – Matteo Cardellini Dec 30 '15 at 23:14
  • This depends on how comfortable you are with Angular. If you have a good grasp of Angular, then picking this up should not be too difficult. – Matt Dec 30 '15 at 23:20
1

Using separate binders like rivets could be a good solution,its easy to integrate and its having rv-each to loop

  • Could you elaborate please (with a link maybe) ? – Matteo Cardellini Dec 31 '15 at 01:29
  • please refer this [link](http://rivetsjs.com/) ,Its a lightweight and comparatively fast binder ,It may help for you ,Its support plain Javascript two way binding, How to use is here [link](http://justbuildsomething.com/agnostic-data-binding-with-rivets-js/) – krishnakumar sekar Dec 31 '15 at 08:02
1

I think the ionic directive collection-repeat might be what you're looking for.

collection-repeat allows an app to show huge lists of items much more performantly than ng-repeat. It renders into the DOM only as many items as are currently visible. This means that on a phone screen that can fit eight items, only the eight items matching the current scroll position will be rendered.

nicfo
  • 450
  • 4
  • 12
  • "If the item-height and item-width attributes are not supplied, it will be assumed that every item in the list has the same dimensions as the first item." - A bit problematic in my case o do you think it can be fixed – Matteo Cardellini Jan 01 '16 at 15:13
  • I've tried it now but if the first message is small and i put a big text the message bubble gets shrank and the other way around if the first message is big – Matteo Cardellini Jan 01 '16 at 15:32
  • @Smile Applications maybe it works if you add the 'item-text-wrap' class to the message-item. – nicfo Jan 01 '16 at 15:39
  • But it's not the standard behaviour that a chat message text is wrapped... It shoud display the full text lenght – Matteo Cardellini Jan 01 '16 at 15:43
  • @SmileApplications item-text-wrap doesnt cut the text, it still displays the complete text using linebreaks, thus it should change the item-height dynamically. – nicfo Jan 01 '16 at 16:06
0

Look at angular-vs-repeat angular-vs-repeat

Demo: demo

I use line length for calculation height of items.

It's very approximate method. In our app we know, that one English character with font-size 15px will have width about 6.7px (that's fine, if you use monospace font, but it's not our case). Also we always know width of each segments and height of one text line. itemHeight = commulativeTextLenght / lineWidth + paddingsOfItem; Also line break stile can affect your calculation. In general we had a not bad method to calculate heights of about 8000 text paragraphs.

  • 1
    Please read the [How to Answer section](http://stackoverflow.com/help/how-to-answer), especially this section: **Provide context for links**. I.e. to exemplify: explain what the links do, and if you have the demo, include code in your answer. – AgataB Sep 02 '16 at 15:08
  • How are you calculating the element height based on the line length ? Can you provide an example of your solution ? – pelican_george Jan 19 '17 at 21:21