AngularJS input slow to fill - angularjs

I have an AngularJS app with a ng-repeat. This ng-repeat displays only about 60 watchers (the list of ng-repeat contains quite big JSON objects though). In the same page I have an input. When I try to write inside this input, it is very slow (displays one letter every second).
I tried to optimize as much as possible but the inputs in my whole app are slow. If I disable the ng-repeat, the inputs goes back to normal speed.
Can someone explain to me why inputs are slow? And if I can solve this problem?

Related

Does AngularJS rendering of a partial block the download of other templates?

So I'm running into an issue on Internet Explorer(works on all other browsers) where it seems like a directive's HTML is taking 20+ seconds to retrieve from the server. The page is set up like this:
<div class="groups-page">
...
<test-directive></test-directive>
<div class="groups">
<h1 ng-repeat="x in records">{{x}}</h1>
</div>
...
</div>
Records is array with about 5000 items. Looking at the networks tab, the groups-page HTML is loaded in several ms. Now since we have 5000 records, I'm assuming it takes a lot of time to render. As a result of this, I see that the test-directive HTML just sits there in the network tab and finally is "downloaded" after 20 seconds. Am I right in saying that I need to limit the amount of data bindings here and that's what is causing the test-directive HTML to take so long to download? If I set a limitTo on the ng-repeat, it makes it much faster the more I limit it.
The issue is most likely due to the sheer amount of work Angular has to do to generate and bind 5,000 copies of your template. What you will see in the browser is that your client downloads the data, and then as soon as it is loaded, it hangs for a while while it generates the necessary HTML to add to the DOM. Once it finishes, the page becomes responsive again and the elements are drawn on the screen. At very large amounts of data, your browser starts to slow down with the number of DOM elements it is keeping track of, even after it is painted.
You have several options to mitigate this, including the following:
Reduce the number of data-bindings in your template
Page your data so that you aren't showing so many at a time
Use "infinite scrolling" (performance gets worse as items are added to the DOM while you scroll)
Look into implementing virtual scrolling for your list (essentially having the DOM only render a portion of the actual results that shifts as you scroll).
I ran into the same issue myself, and ultimately went with option 4. It is probably the most work out of options above, but the solution is handling an array of 200,000 items quite smoothly. If you don't want to create your own virtual scroll, there are a handful of open source implementations out there now that are worth looking into.

Is there any way to avoid ng-repeat?

I am using multiple ng-repeats in the ionic view to show json data, i can get the data in console in no time but I guess having multiple ng-repeats has slowed the perform altogether, which cause the app to freeze and takes a minute or so for the data to appear on the view.
Is there an alternate way , to avoid speed up the performance. ?
You can use collection-repeat.
collection-repeat allows an app to show huge lists of items much more
performant than ng-repeat.

Overcoming UI blocks when updating ng-repeat data

So yes, apparently it is possible to have long grid with lots of rows built with angular. But then a problem comes with data updates.
You see if I just get all (let's say 10 000 rows) and render them in my grid - that works. It just takes a few seconds initially. And
a) I don't have all the date up front
b) I need the grid to be responsive immediately.
I can just do that with throwing let's say only 100 rows at the beginning, and then slowly update data as it becomes available. And that turns out to be the problem. Everytime you push new rows into $scope.data - it blocks UI. So I need to be smart about these updates.
Maybe I should set an interval and update the data only every few seconds? That seems to be not working
Maybe I should somehow watch for mouse movements and once it stops moving - start/resume adding rows, once mouse-movement detected seize adding rows and wait for another chance? - What if user never stops moving the mouse? (say some sort of a psycho)
Experimenting with _.throtle and _.debounce didn't get me anywhere.
You guys have any ideas?
UPD: here's a crazy one: what if? instead of waiting till angular updates the DOM, create entire DOM structure in memory, right before the digest cycle (with no data) and then insert that HTML chunk (that would be faster, right?) And after that let angular do its magic, data should appear. Would that work?
You are going to run into performance issues when something changes even if you can get all those rows rendered to the DOM. And your user probably isn't going to scroll through 10000 rows anyway. I would just use pagination. e.g.:
<div ng-repeat="item in items | startFrom:currentPage*itemsPerPage | limitTo:itemsPerPage"></div>
If you really want to have everything on one page you could load the rows as the user scrolls. If you are interested in that solution checkout http://binarymuse.github.io/ngInfiniteScroll/
One of the things I've noticed that I stupidly used to ignore - the container has to have fixed height. That significantly makes updates faster. Although technically it doesn't solve the problem entirely

How to stop a $digest loop apparently caused by a filter

Consider the following Plunker:
http://plnkr.co/edit/10Rs92cRulf9VtI3Bav6
It appears to work correctly, but if you look at the console, you can see that something is wrong. With just that little table, Angular has already hit the Digest loop limit of 10!
it isn't a problem in a small dataset like this one, but the actual production page has 10 different filters and can span 30+ days. As the data grows, the $digest looping is getting way, way out of hand.
What can I do to stop it? I have been pouring over the source code trying to figure out why the Table keeps getting digested over and over and over again, even though the data isn't changing at all. Am I missing something?
Filters are really for massaging data for the view.
The filter on your ng-repeat that loops and creates the date range is causing the issue. ng-repeat is calling that filter every. time. it. 'repeats' :) and from what I can gather you only need to create the range once at start-up (or when data changes). If you move the date range creation code out of a filter it should be more performant. You might even consider moving the range creation server side.
Forked your plunkr http://plnkr.co/edit/XTn7hjbQgV1DxcBlOYVJ.

how can I exclude an element from an Angular scope?

my premise was wrong. while AngularJS was certainly slowing things down, it was not due to the problem I describe below. however, it was flim's answer to my question - how to exclude an element from an Angular scope - that was able to prove this.
I'm building a site that generates graphs using d3+Raphael from AJAX-fetched data. this results in a LOT of SVG or VML elements in the DOM, depending on what type of chart the user chooses to render (pie has few, line and stacked bar have many, for example).
I'm running into a problem where entering text into text fields controlled by AngularJS brings Firefox to a crawl. I type a few characters, then wait 2-3 seconds for them to suddenly appear, then type a few more, etc. (Chrome seems to handle this a bit better.)
when there is no graph on the page (the user has not provided enough data for one to be generated), editing the contents of these text fields is fine. I assume AngularJS is having trouble when it tries to update the DOM and there's hundreds SVG or VML elements it has to look through.
the graph, however, contains nothing that AngularJS need worry itself with. (there are, however, UI elements both before and after the graph that it DOES need to pay attention to.)
I can think of two solutions:
put the graph's DIV outside the AngularJS controller, and use CSS to position it where it's actually wanted
tell AngularJS - somehow - to nevermind the graph's DIV; to skip it over when keeping the view and model in-sync
the second option seems preferable to me, since it keeps the document layout sane/semantic. is there any way to do this? (or some, even-better solution I have not thought of?)
Have you tried ng-non-bindable? http://docs.angularjs.org/api/ng.directive:ngNonBindable
<ANY ng-non-bindable>
...
</ANY>

Resources