AngularJS performance with many directives - angularjs

I'm using AngularJS 1.0.8.
The problem: I have a dynamic website that can be built from various components, or widgets: paragraphs, text blocks, images, hyperlinks, and tables, for that matter.
A paragraph is a container of more components. A table is also a kind of a container - it can hold other components, and it arranges them as a datagrid.
The website is not static, i.e. I don't have a pre-defined layout of such components.
Instead, I get a JSON in startup, that specifies the layout of the components.
Originally, I had a directive of each such component, using templates for that directives, and occasionally using $compile to change the DOM a bit for more complex components.
For the 'container' components - paragraphs and tables - I used ngRepeat to render all of the components that are contained in that container-component.
That was problematic performance-wise. It would take the website many seconds to load on Chrome/Firefox, with the time spent mainly in the AngularJS render mechanism (not in IO, I figured).
So I decided to change the directives of these components. Instead of using ngRepeat, which is not really necessary since I don't need the two-way binding (the content in the website is not interactive and cannot be changed, so really I only need to render it once, very much like a servlet) - I built the HTML string in the directive myself, using plain JS, iterating over all of the contained components that exist in the model, and at the end I $compiled and linked it.
The result wasn't good enough again.
For a table of a few hundered cells, it took ~500 milis to link in modern Chrome/Firefox, and ~4000 milis in IE9, and ~15000 milis in IE8, and IE7 is still rendering so I can't give you the time :)
I thought that the problem might be with an extensive use of directives.
A simple:
<div my-table-component data="data"></div>
element would result, after the link, in a <table> tag with 30-40 <tr> tags, each with 10 <td> tags, and in each there would be an additional <div my-text-component> or <div my-image-component> that would then have to be compiled and linked by itself (since it has a directive).
I though that since my website is not interactive to begin with, I don't really need this.
Maybe I could avoid using directives for each component, and leave only a directive for the container-components. In these directives, I would create the actual HTML template of every possible other component, instead of using directives that would do that.
That takes me another step away from the AngularJS idea towards a servlet idea. And it kind of sucks.
So maybe one of you can offer a better approach for me... Maybe the performance problem is not even there? Maybe a use of directives (and hopefully ngRepeat) can be fine performance-wise even with this amount of items? Maybe there's a better way to make an insightful performance benchmark, other than using Chrome's Developer Tools, Firebug, and Chrome's Batarang AngularJS extension (none of them really directed me in a productive way).

Using a lot of nested directives by itself is not a problem, but any extensive binding could have huge impacts.
If someone is still looking for an aswer to this, using Angular 1.3+, OP could solve his problem by first using one-time binding on all the elements on which he says there is "no need for two-ways bindings", using the ::binding syntax.
In addition, I would suggest trying to spot which bindings exactly are being particularly slow, using the amazing profiling snippets from this website: http://bahmutov.calepin.co/improving-angular-web-app-performance-example.html
Finally, what often takes most time in Angular, especially while building big ng-repeated tables, is the compilation phase. So if possible try to only build a restricted number of elements (using limitTo) and then load more as the user scrolls for instance. Many directives address this concern (look for "infinite scrolling")
All in all, I think it is still worth trying to optimize an Angular application rather tham switching to native JS, most of the time the lag comes from a developper mistake: some applications have thousands of watchers and run pretty smoothly (*cough* like mine *cough*).

Related

finding xpath for elements in applications built on angularjs

The application under test is built on angular because of which the xpaths are failing to locate the element . I am using selenium web diver for automating the tests and google chrome browser.
Can anybody kindly specify how to break down angularjs components to basic html elements while creating the xpath or any other way i can adapt to find the exact element on the page.
Any link or path or tips to follow.
I have searched a lot but no luck till now.
Starting with covering some general concerns.
When testing AngularJS applications, the timing issues are usually the most common - this is partially why we have tools like Protractor built mainly to test AngularJS applications. What makes it unique is that it works in sync with Angular, knowing when it is ready to be interacted with. It also provide AngularJS specific locators which makes locating elements much easier, samples:
element.all(by.repeater("item in items"));
element(by.binding("mybinding"));
element(by.model("mymodel"));
If you can, you should consider switching to Protractor - the test flow is natural - almost no explicit waits, a lot of convenient syntactic sugar and much more element-locating options.
If not, you can still use Angular-specific attributes to locate elements, examples:
driver.findElements(By.xpath("//*[#ng-repeat='item in items']"));
driver.findElement(By.xpath("//*[#ng-binding='mybinding']"));
driver.findElement(By.xpath("//*[#ng-model='mymodel']"));
Though, as usual, you should prefer to use ids, classes and other "data-oriented" attributes.
Things can easily go wrong with the above sample expressions - imagine web developers add a "tracking" to the repeater, or rename the ng-repeater to data-ng-repeater.
As a side note, using Angular specific things like ng-* attributes in your tests, would make the test codebase tight to this specific technology used to build the application under test. It is not necessarily a bad thing but you should keep it in mind.

Why would you use lodash in AngularJS?

Simple enough question I think. I see people raving about it but I haven't seen anything on the "why" use it. It doesn't seem to me (from my naïve outside perspective) ng-repeat, if not in that nested layer do ng-repeat inside another. I looks like that it doesn't add functionality that angular doesn't already have—I'm sure I'm wrong—
I see the term "lazy loading" being used with it and it doesn't seem like it's that much easier after seeing there docs. What are some things lodash makes significantly easier in AngularJS specifically that I would make it work adding another lib to my project? And what can you do with it that you cannot with angular out of the box?
They're just not the same, and exist for distinct reasons. I think you already know what AngularJS works for, so about your questions:
What can you do with it that you cannot with angular out of the box?
Well, if you need to deal with several data in structures like arrays, objects or mixed/nested shapes, lodash will save you a lot of time and effort.
Maybe there's a lot of items in collections which should be presented to your client application in some particular way, you would have to write a lot of JS code in Angular controllers or services with out the aid of lodash.
If there's a lot of logic tied to your data structures and/or complex algorithms and coding workflow, go for lodash.
Lodash is a great tool, you can get some intro here and of course, just check out the API reference. You can use it at everywhere, either Angular or any other framework, and of course, also at Node too!

Using directives in real life angular app, are directives with controllers a right approach?

I know that this topic was discussed many times but I'm still not quite sure if I'm doing things right..
Many on-line resources embrace directives as a building blocks of the angular applications, in the same time many resources emphasize re-usability of the components. Anyway from my experience when I build typical app, there is not much things to re-use, usually each component has single role and it is used in the single place. As I understand angular, one of the main concepts is to provide semantic DOM, and in order to achieve that we can use directives. So when I build an angular app usually I create a set of directives and combine them in the views.
In my apps in the most cases all the DOM manipulation can be done using the build in directives. Most of my directives has a template and a controller, I do not need to use link function. In most of the resources in the internet I can read that I should use link function when creating directives. But this seems to be far more complicated code... . What is the benefit of the link function if I don't need any fancy DOM manipulations that are beyond build-in directives ?
tldr; I build my apps using directives with controllers and put them into views, is this a right approach ?
I've been developing in Angular over a year now on an enterprise level application and my team has gone by a standard of creating directives if you are using that same element more than once. It saves time, saves the DOM trouble, and makes it easy to create separate, testable pieces of code.
We've created directives for many listing items that use ng-repeat. Pretty much every ng-repeat we have is iterating over a directive to create true isolate scope in our elements' functionality. It's one of the most powerful features in AngularJS when done right and conforms to the standards of Object Oriented Programming where you can really make your applications use abstraction to the finest degree. Here's a wiki link on abstraction.

Get AngularJS template bindings

I am working on something like CMS based on AngularJS templates. I need to get bindings from a template so my users are able to fullfill those properties for specific pages.
So how can I get all bindings from a template?
You can't... using techniques AngularJS itself provides. Your question is just beyond the scope of the functionality the core devs thought to provide.
#bmceldowney is correct - a regex could be used to parse templates, although I think that would be challenging for a few reasons:
AngularJS templates can contain all sorts of complex expressions, not just simple vars. How will you deal with filters - and if you won't, you lose a lot of value here...
AngularJS can lazy-load templates and this is a common practice. You wouldn't want hundreds of useless templates floating around just in case they might be used at some point. How will you deal with templates that haven't been loaded yet - that you don't know exist?
If you're building a CMS that implies data management of some kind, and that's not going to get stored in the front-end because it would be useless there - nobody else would ever see it. So aside from the editing cycle itself, it seems like something to be solved server-side and not with AngularJS.
All that said, my suggestion would be to do exactly that - work out something server-side where you can access templates as raw files just by scanning some folder where they're stored, use regular expressions to find the template variables, and you're going to have to be clever with how you parse expressions and what you'll support here. Then you can prepare appropriate data objects to pass down to the client via an API for it to support the actual editing.

AngularJS: Is ng-click "a good practice"? Why is there no ng-{event} in AngularJS?

I just started to learn AngularJS and struggle with some concepts of AngularJS. It would be great if somebody could explain me some points...
I understand that ng-click is technically not the same as onclick (see here), but both are placed in the markup. I thought that would be a "bad practice"? Why is this one of the core concepts of AngularJS, if most people say this is "bad"? I thought it would be better to select the DOM element from JavaScript and not to place logic in the markup.
If ng-click is the right way to react to click events in AngularJS what should I do with other DOM events? I see that there are several other directives like ng-mouseover, but not all DOM events have a AngularJS equivalent. How would I handle a 'drop' event in AngularJS (hence in the AngularJS way - not the normal way)? To be clear: I want to drag a file into my webapp.
Thank you very much,
Pipo
Why is this one of the core concepts of AngularJS, if most people say this is "bad"?
Well, people who really like Unobtrusive JavaScript might say it is bad. Angularians (and those with a flex background) see value in the more declarative approach.
"Angular is built around the belief that declarative code is better than imperative when it comes to building UIs and wiring software components together... By declaratively describing how the UI should change as your application state changes, you are freed from low level DOM manipulation tasks. -- Overview doc
See also Don't the data attribute options used in Bootstrap, Angular.js, and Ember.js conflict with Unobtrusive Javascript principles?
what should I do with other DOM events?
Write your own directives to listen for them (or find one that someone else has already written). Angular gives you the power to extend what the browser can do -- by writing your own directives.
Update: in the comments below, Tim Stewart mentions AngularUI's ui-event, which lets you bind a callback to any event not natively supported by Angular.
By nature, Angular requires elements in the markup in order to function properly. Further, those elements must be "compiled" each time they change, for the most part. So, it's already somewhat "obtrusive" irrespective of the JavaScript. You can't simply replace the markup, and have everything auto-bound for you like you can with something like jQuery.
Strictly speaking, unobtrusive JavaScript:
1. separates structure and behavior, in order to make your code cleaner and script maintenance easier
2. preempts browser incompatibilities
3. works with a clean, semantic HTML layer
(Wikipedia)
That's not Angular, for sure. In order to achieve the two-way binding on everything, they chose to make custom binding points in the DOM, as opposed to using a class name or ID the way that jQuery would do. (A somewhat non-standard approach, but it obviously works.)
But the real way to think of it is this: Basically each controlled section of your markup is not really straight HTML anymore anyway. It's really more of a template now, and as such requires interaction with the engine that is preparing it for rendering. As such, the traditional rules of unobtrusiveness don't really apply... (FWIW, I'm a huge fan/user of the jQuery.on() function to bind elements to events automatically when the element is added to the page. Very clean and flexible, IMHO, and I do wish there was a similar mechanism in Angular. I like adding a class to items in multiple locations on the page that invoke the same event handler automatically. Having a single place to go change code is a good thing. but I digress...)
For me, the bigger issue is that of progressive design. Does the web page work without JavaScript enabled at all? Does anyone really care about that? Hmmm...

Resources