Optimizing AngularJS ng-repeat for many items and fields - javascript

Recently I had to make an interface that necessitated many items with numerous checkbox fields to be displayed and interacted with (here is a link to a screengrab of a small portion of such a list http://i.imgur.com/hMtGSL4.png).
My issue was that AngularJS would get unreasonably slow pretty quickly. My question is What steps could one take to optimize ng-repeat and displaying items with many fields?
I have tried with varying degrees of improvement (based on what I could come up with and other stackoverflow posts):
Formatting the data before it gets to the view so as to not use any AngularJS filtering/sorting.
Simplifying the data as much as possible (checkbox fields being arrays of booleans, etc)
Splitting the data into groups that, when clicked, loaded the relevant items (hence the gray bars in the picture). This is more of a pragmatic solution though, rather than straight up AngularJS optimization.
Lazy loading scroll, scrolling to the bottom of the screen loads more items below the fold (also, more of a pragmatic solution).
Using directives to dynamically generate a form, and then use jquery for saving the data after manipulation. Without $watch on items anymore it certainly was more efficient, but largely defeated the benefits of using AngularJS.
Thank you, and hopefully this question and its answers can serve as a good resource for AngularJS specific techniques one can use in such a situation.

Related

Limitation of Angular and browsers with regards to data loaded

I would like to know what is the maximum data that angular framework can handle. Say, I am displaying a chart using angular and some charting framework like chartjs. I'd like to know up to how many data can the browser display properly, with slowness, or up to when it crashes.
Your question has no simple answer, but I will try to flatten it and give a simple answer, or at least simple things to consider...
Angular (at runtime), like many other frameworks is simply JavaScript,
So let us reduce the question to "Limitation of JavaScript and browsers with regards to data loaded",
JavaScript has no upper limit of memory or storage it can handle,
I've seen JavaScript applications that require more than 15GB of RAM,
and they performed well too.
So assume data size itself is not an issue (unless your application is poorly implemented, leaking memory or just not very efficient, of course).
The main challenge as I see it, is displaying and manipulating the information
without causing unnecessary delay or unresponsiveness.
Displaying the information - let's say you have a list (or a table) containing 1,000,000 possible gifts which you then want to display for the user to select.
Adding the list items to the document one by one is tempting, but will require the browser to repaint after each addition (causing a delay or full unresponsiveness until finished), another way is adding the elements to some DOM element (denoted by N) still being kept in memory, then adding all elements corresponding the list items to the element N (still, just an in memory operation), finally adding N to the document containing the entire list - the will be a much better solution for displaying the large amount of data.
Manipulating the information - displaying is indeed not enough. you would like to move, drag, sort and filter the data being displayed. And as mentioned before, it is a bad idea removing many elements directly from DOM. You should instead remove container from the document's DOM to memory, manipulate the data in it, and then add the container right back to the document. Angular does this kind of magic for you.
(Toggling the 'display:none\block' css attribute of many elements has a similar blocking effect as I recall).
A good practice is implementing an application/page showing only the amount of data that can be processed by a human at a single glance. The rest of it should be considered in the application data-layer, in memory, and should be loaded to display given the appropriate need or request.
To conclude, you can deal with huge amounts of data as long as you provide a mechanism that efficiently filter the displayed information.
I hope it helps...
for further reading:
Slow and fast ways of adding elements to DOM
A question emphasizes the lack of memory limit used by JS
CSS display attribute performance
A good discussion about the reasons for slow DOM
About using HTML5 correctly - old but still true
Once the DOM creation procedure is understood - it much easier to display data without affecting performance / user experience

Way to implement lazy loading in Angular

I currently am working on a web application based on AngularJS. On few screens, I have to repeat an array object to display multiple tiles on screen.
The data however is not much but the rendering on DOM is taking too much time, due to multiple directive compilation for each of the tiles.
On another screen, I am using highcharts library to plot 4 series for each such object in the array.
So, to improve the performances, I am thinking on the lines to restrict DOM rendering only to view-port area. I have gone through few external libraries in jQuery that provides such implementation but I am looking for a pure and simple AngularJS based idea.
One thing I tried was using limitTo in ng-repeat. It reduces DOM manipulation to limited data. However, I am looking for a technique that would fetch data from server as and when required as per user scrolling.
Is there a simple method to do so on Client side? Should I go for handling scroll event and call server for data.
An easy way to improve performance is indeed by paging the results. If you want to page items by scrolling you might want to take a look at ngInfiniteScroll.

How to speed up AngularJS rendering with big scopes?

I'm developping an angular app right now for my company, but I reached a point where the app became extremely slow so I tried tunning it by using onetimebind everywhere I can, track by ...but it's faster to load at first but still laggy, it is composed of a pretty much huge nested objects, I've counted the total number of objects, it starts at 680 and can go up to +6000 for normal use of the app, oh yeah I should precise that the app is generating a form and pretty much +90% of the objects in the scope belongs to an input and are updated each time the client click(radio) keyup/change(text).
It also have like 5/6 arrays composed of objects and the array gets bigger/smaller accodring to the clients choice, and that's where it gets laggy, each time I add an object to the array, it takes like a second to render it, so I tried using nested controllers thinking that if the child of an object is updated Angular will render only this child and not all the others, but somehow the app got even slower and laggier :s (it's a bit faster when I use ng-show instead of ng-if but the memory used jumps from ~50Mb to ~150Mb)
I should also precise that the form is in a wizard style, and not all the inputs are displayed at once, the number of inputs that are displayed are between 10%-20% of the total inputs
Has anyone encountred this problem before? does anyone know how to deal with big scopes?
Sad to say, but that's intrinsic of the view rendering in angular.
An update in the model triggers a potential redraw of the entire view. No matter if you have elements hidden or not. The two way data binding can really kill performances. You can consider evaluate if you need to render the view only once, in that case there are optimizations, but I'm assuming that your form change dynamically, therefore a 2 way data binding is necessary.
You can try to work around this limitation but encapsulate sub part of the entire MVC. In this way a contained controllers only update the specific view associated to that scope.
You may want to consider using react (that has as first goal to address exactly your use case)
Have a look at this blog post for a comparison of the rendering pipeline between angular and react Js.
http://www.williambrownstreet.net/blog/2014/04/faster-angularjs-rendering-angularjs-and-reactjs/

What's a good JavaScript grid with tabs?

I have 3 sets of tabular data I want to display with a JavaScript framework in ASP.NET MVC. I know I can embed a separate grid in a tab, but this seems inefficient especially when large datasets are involved since I imagine 3 separate grids would be created. I haven't found a JavaScript datagrid which emulates what a spreadsheet does with multiple tabs. This example from YUI might come close though:
http://developer.yahoo.com/yui/examples/datatable/dt_dynamicfilter_source.html
I'm a little familiar with jQuery, but would be willing to switch to any framework which makes this easy. I don't really need to edit the data. Any suggestions?
EDIT: I didn't mean this to be about jQuery. Maybe some details about my scenario would help, as suggested in one of the comments. I want to display tabular data from an ordering system containing thousands of records. I'd like 3 tabs:
All orders entered in the system which haven't been paid for yet.
All orders from a specific vendor.
All orders which have been paid for.
Since each category has thousands of rows, I only want to load data if the user starts paging.
I thought having 3 tabs with 3 separate grids (one within each tab) wouldn't be performant. I haven't actually tried though, so I'm probably guilty of prematurely optimizing. I'm looking for a grid with tab support built-in. I don't think there's one for jQuery. Perhaps ExtJS?
Since you tagged this with Ext JS, I'll mention that it's quite simple to render grids into tabs using Ext JS. It also supports deferred load/render, so that only the first tab/grid would load initially, then the others would be loaded on first access. Without knowing your specific requirements it's hard to comment further.
EDIT (based on edited question): Ext grids don't directly support tabbing, but they can be embedded within a TabPanel as I mentioned for the same effect. However, based on your description, it sounds more like a filtering scenario to me. I don't see the point in having the overhead of multiple grids when only one will ever be visible, and each one's purpose is to show a specific view (i.e. filter) of the same data. I would just have a single grid with a toolbar or some other method of providing your toggle between filters, and use Ext's built-in store filtering/querying to create your views on demand. The Ext grid supports paging out of the box (client or server, in your case it would be server for thousands of records). There is also a very popular plugin called LiveGrid that provides for virtual scroll-paging of large data sets.
I'm not necessarily advocating Ext over any other framework -- I just happen to be most familiar with it and I think it could solve your problem quite nicely. I would suggest trying it out for yourself to be sure.
jQuery Grid is kinda what people use a lot. I use it and it's pretty good.
jqGrid Link
I wouldn't draw a grid with three tabs. I'd use a single grid with a tab control and then load data via jQuery as required.
Or maybe have three PartialViews that you can load dynamically when you hit a tab.
You could also use dhtmlx grid.
You could use JS tab object to create tabs.
And use javascript grid framework to create grids and populate data into grids.

Alternatives to a single <select multiple="multiple"> element for large datasets

I'm often conflicted about how to approach this problem in my applications. I've used any number of options including:
A generic multiselect - This is my least favorite and most rarely used option. I find the usability to be atrocious, a simple mis-click can screw up all your hard work.
An "autocomplete" solution - Downside: user must have spelling abilities to find the damn values they need, aren't exposed to ones they may not have in mind, and the potential backend performance of substring searching.
Two adjacent multiselects, with an add/remove button - Downsides: still "ugly" imo
Any number of fancy javascript solutions (http://livepipe.net/control/selectmultiple, http://loopj.com/2009/04/25/jquery-plugin-tokenizing-autocomplete-text-entry/, etc.)
I haven't been able to find any usability studies done on the best approach to this problem. Many of these alternate solutions are great when you're going from <10 elements to a hundred, but may break down completely when you are going from a hundred to a thousand.
What do you guys use? Why do you use it? Can you point me to usability case studies? Is there a "magic" solution that has yet to be discovered?
My advice is don't use generic multiple select controls. I've been running User Experience Research for my whole career, and every single time I test a site with multiple select controls, it always turns out to cause problems for end users.
I did a post on this a while back: Multiple Select Controls Must Evolve or Die
Sounds like you knew this anyway, though. Your real question is "what do I use instead?" Well, to answer this question you have to work out whether the user's task leans towards recall or recognition.
(i) By recall, I mean the user knows what they want to pick before they have even seen the list. In this case, it's probably easiest for them if you offer an autocomplete tool (as used very effectively on facebook, for example). This solution is even better when the list of options is also impossibly long to present on a page (e.g. location names, etc).
(ii) Moving on to recognition - by this I mean a task that involves the user not knowing what they want to pick until they've seen the list of options. In this case, autocomplete doesn't give them any hints. An array of checkboxes would be much more helpful. If you can show them all at once, this is helpful to the user. Scrolling DIVs are more compact but they create a memory load for the user - i.e. once they've scrolled down, they have to remember which items they picked. This is particularly evident when users save a form and come back to it later.
So - thinking about your problem, do you need a solution for recall or recognition?
I can't point you to any case studies, unfortunately, but what I can tell you is that I personally prefer large checkbox arrays in two-to-five column layouts. Sure, they take up a lot of space, but they are extremely precise and uncomplicated.
I think for any control - be it basic multiselect, double list, checkbox array, or any other solution - once you go over a certain threshold of items it's going to be challenging for the user no matter what.
Have a look at Dojo Toolkit's DataGrid control. It's by far the most flexible and powerful, and supports multiple row selections. It also has accessibility features built in.
The ExtJS library has some really good solutions for your issue. There a bunch of user extensions for neat-o combos and multi select boxes.
If you want a combo select list, you can add query searching and pagination, plus design the resulting drop-down using easy templating, like in this example:
http://extjs.com/deploy/dev/examples/form/forum-search.html
Here is a nice multiselect, in the style you seemed to describe:
*(main_site)/learn/Extension:Multiselect2
You can find all user extensions here:
*(main_site)/learn/Ext_Extensions
Plus, you can easily include it into an existing web page without alot of extra overhead. ExtJS's full stack is quite large, but to get only the JS files you need, they provide a nice builder tool to grab just those parts you need:
*(main_site)/products/extjs/build/
Just a warning: ExtJS has just released 3.0, but I'm not sure the user extensions have been upgraded. The "forum-search" was taken from a 3.0 example though, so it will work just fine with the latest and greatest.
(*) Apparently new users can only post one link...

Categories

Resources