Is there guidance around using too many directives with AngularJS? - angularjs

Is it bad practice, form-wise or performance-wise, to use directives for 'everything'? I'm beginning to see them as functions for rendering HTML, and like functions, they become useful when they are very discreet and combined.
However, I'm starting to get concerned that this might lead to poor performance or directive-overload. Here's an example of how I would like to use them - I am interested in feedback, especially about performance, etc.
<!-- This could even be wrapped in a my-editing-area-navbar directive -->
<my-navbard heading="{{pg.constants.navHeader}}">
<my-jump-to-page></my-jump-to-page>
<my-divider></my-divider>
<my-undo></my-undo>
<my-redo></my-redo>
<my-divider></my-divider>
<my-clear></my-clear>
<my-accept-and-continue acceptFunction="pg.acceptAndContinue()"></my-accept-and-continue>
<my-divider></my-divider>
<my-reset-utility></my-reset-utility>
</my-navbar>
<my-left-column heading="{{pg.constants.leftColHeading}}">
<my-preview-component></my-preview-component>
<my-debug-utility ng-if="{{pg.showDebug}}"></my-debug-utility>
</my-left-column>
<my-main-content heading="{{pg.constants.mainHeading}}" subheading="{{pg.constants.mainSubheading}}">
<my-message-viewer></my-message-viewer>
<my-content-mainpulator>
<my-content-frobber></my-content-frobber>
<my-dohicky></my-dohicky>
</my-content-mainpulator>
</my-main-content>
</my-page>

In my opinion, almost anything that's small, modular, and reusable should probably go in a directive. Keep it DRY. If it's really specific to the controller/view, there's really no need to abstract it away into its own thing.
I can't say much about performance, but none of the directive heavy apps I've worked on have felt sluggish or anything. And I'm willing to trade what performance loss there might be for the encapsulation and reuse that directives provide.
I see directives just the same way as any other specialized html element (input boxes, text areas, etc), and use them the same way (this makes more sense when you know that angular is heading towards using the Shadow DOM). Just make sure it's coded up well and you shouldn't see performance issues.

Related

Custom class or attribute in E2E testing

Having pretty complex angular application with many pages (states) and conditional sections that creates a lot of test scenarios I need to perform e2e tests. I'm tired of nested selectors like 'div.SomeComponent > ul:nth-child(2) > ... ' and so on even using BEM namings (especially when app is evolving and it's easy to spoil tests by little change of html structure).
The question is, would you guys opt for creating some dummy (empty) classes or data-* attrs just to simplify protractor (or groovy) selector at the expense of loosing semantics? What's the alternative?
To avoid changing your element definitions every time developers change the css and to avoid using long css strings to select your elements, you can try referring to them by other means (id, className, model, etc.). See https://github.com/angular/protractor/blob/master/docs/locators.md for examples.
My personal favorite is to use element(by.css('[ng-click="executeSomeAction()"]')) as this will most likely not change with any application updates. It also works for other directives as well.
As for testing applications with a high volume of pages and elements, it's nice to define your elements in a class(es) and then call them in the test spec as needed. This reduces the code in your specs and makes them easier to read. You may also want to create a separate file for actions/functions your tests perform.
Hope this helps answer to your questions.

the place for simple logic in an angularJS application

I would like to know which is preferable in an angularJS app.
in the html, I can have...
a)
<span ng-class="{'car-icon': category === 'CAR' || category === 'SUV','bus-icon': category === 'BUS','bike-icon': category === 'BIKE'}"</span>
or...
b)
<span ng-class="categoryIcon"></span>
where categoryIcon is set in a controller function.
My preference is for b). a) puts logic in the UI which I do not like. I also find it much easier to test controller functions, so another reason for b)
However I'm being told that a) is the way to go because that is what angularJS templating is for. The example is applying CSS styling however I'm getting the same reasoning for setting href's, there is some simple logic required and I'm being asked to do it in the HTML templating vs a controller function.
It's a matter of preference, but I much prefer option b)
<span ng-class="categoryIcon"> with categoryIcon set in the controller.
If you think ahead, what if new categories are added, that html is going to get long, ugly, and error prone. Also, what if you want to use categoryIcon in multiple places in your html in the future. Simply referencing ng-class="categoryIcon" is much better design than copying option a) to multiple places.
I don't know why the other answers here have been down voted, since this is an opinion on best practices and there is no concrete right/wrong answers, but I would prefer solution A in one-off usages, and a solution hinting at B when it has to be repeated in the view.
I tend to think that the view should be able to handle the data model as it sees fit. It's not really business logic that we're talking here, and I don't want to have to jump into the controller code to see what class is being passed.
If you are making use of this conditional all over the place, though, it certainly would make sense to at least create some convenience methods in the controller: isCarSuv(), isBus(), etc. Then the ng-class conditional blocks would be cleaner.
<span ng-class="{'car-icon': isCarSuv(),'bus-icon': isBus(),'bike-icon': isBike()}">
I don't really think a pure B style implementation is the way I would do it.
Just my two cents. Others are sure to disagree.
I always use this variant since it is way cleaner, but i guess this is from developer to developer different
<span ng-class="categoryIcon">

Angular directives - element or attribute?

I'm part of a team with about 6 UI devs, of varying quality and next to no Angular experience. Many are contractors, with little experience with the code base. The app has a very fancy (complicated) UI. It supports IE8+ (soon hopefully IE9+).
We're introducing Angular for a major extension to the app, and I've been asked to write guidelines on the use of Angular for the team.
We'll use directives to create fancy UI elements, all prefixed with "ipwr" to avoid name clashes. I'm trying to decide whether to mandate that devs give their directives the restriction "element" or "attribute". Mandating only one, to avoid chaos and confusion.
My question is: what restrict is better or more popular for directives, "element" or "attribute"?
My main concern is ease of use for people with little Angular experience who are new to the application code base, to reduce bugs, copy and paste behaviour, etc.
The angular guidance says that you should use the "element" restriction whenever the directive has full control over it's template meaning it has a template that it is rendering out, etc.
For attributes, they suggest to use these only when you are adding "behavior" to an existing element or decorating an existing element.
For example, think of the ng-click directive, this is used a attribute not as a element because the click directive is just adding the click behavior to some element.
Another example would be the ng-repeat directive, it is also used as an attribute not as a element because it is going to repeat the element in which it is being used in.
Now, this guidance is from the angular documentation; however, I don't know necessarily that element vs. attribute is going to give you a "better" approach it's more of a convention.
Now if you have to support older browsers, then you may want to consider using either the comment or class directives.
My personal preference is to just use the attribute restriction; mainly because people that are new to angular get overwhelmed at first when they see the restrict and it's variations of the options that can be used.
I usually defer to the John Papa AngularJS style guide when making these types of decisions. He says:
Lean towards implementing as an element when its standalone and as an
attribute when it enhances its existing DOM element.
If you want to keep your HTML valid you'd use attributes, e.g. if you have a directive ipwr-modal, you can declare it as <div data-ipwr-modal="you-could-put-some-binding-here"></div>.
When creating directives with a custom layout, however, you'd better use element declaration (if you don't need to have your HTML valid). This is the more obvious way to say: "hey, we have a custom component here".
This blog post explains it with some more ideas
Some points to consider:
Most of the time attributes is the best/most convenient option (it's not the default by chance).
Anything you can do with element-bound directives, you can do with attribute-bound as well.
Element-bound directives can be more descriptive/readable at times.
If you want your code to pass certain types of validation, you should use attributes.
Since you want to support IE8, keep in mind that custom tags have an extra overhead (more info), which hurts maintainability.
BTW, you can't limit directives to elements only (without affecting functionality), so it is more a question of allowing 'element' or not. Note that an element often has more than one directives and directives placed on the same element can cooperate and augment each other's behaviour. So limiting the use of directives to 'element', means limiting the number of custom directives per element to 1, which severly reduces the functionality-potential.
That said, this is what I ('d) do:
If IE8 is not an issue, allow both (mostly use attributes).
If IE8 (or the overhead for custom tags) is an issue, use only attributes.
In general, if only one form should be allowed, it should be attributes (works anywhere, no extra overhead, offers all functionality).

Angularjs: Find all instances of a directive

I'm trying to create a directive to allow the user to navigate the page with arrow keys by section. But I also want to be able to have those sections be scattered around the dom, and to have this not break when stuff gets added and removed. I can think of several ways to do this, but none of them are satisfactory:
Create a directive with a controller that lets other directives register themselves (and unregister on $destroy). But this will be out of order if I add something in the middle later. Also, I've tried writing it this way, and it seems like way more code than necessary.
Whenever the user hits an arrow key, make an empty array, and $broadcast an event, with a callback for directives to register themselves on that list. Then, once that list is full, advance or go backwards on it. They (should?) come back in the order they're in on the DOM, but I'm not sure since this way seems crazy and hackish.
Mark things that are 'tabbable' with css, and write this the simple way in jquery, something like this: On a new click event, var all = $('.tabbable'), and then do the obvious with that. But I really don't want to do it that way, because it's not 'the angular' way. Not out of some sense of purity, but because I'm building this as part of a larger library of widgets, and I want this functionality to be accessibly to them.
So, is there any way for me to get the scopes of all directives of a certain type, without resorting to weird hacks, or spreading the logic out all over the place?
This is a good question. +1
First, finding all directives or nodes by type goes against the Angular way. The View is the official record in AngularJS, so directives should say what they do and do what they say. Coding some process somewhere to scan for DOM nodes and act accordingly is problematic for several reasons, not the least of which are separation of concerns and testability.
I'm glad to see you're looking at other options, but I agree that the other options you provided are sub-optimal for the very reasons you mentioned. But I have one more. This is one that I've used for a different application, but that required knowledge of scattered DOM nodes.
First, we create a service to manage the state of this component. It's simple. Let's call it SectionsService. Next, we create a directive to register sections. Let's call that section for simplicity. The section directive registers the DOM node's ID (maybe created programmatically to ensure uniqueness) with the SectionsService during its linking phase. Since the DOM is processed (mostly) in order, the nodes added to the SectionsService will also be in order. So the DOM looks something like this (irrelevant stuff omitted):
<div section>...</div>
<!-- other stuff -->
<div section>...</div>
<!-- other stuff -->
<!-- etc. -->
(Though out of scope here, it would not be very difficult to program it in such a way that the order wouldn't matter, but it'd be based on specifics of your app that I don't know.)
Next, you create your triggers, like an arrow key handler. On these events, you simply tell the SectionService to go to the previous/next node in the list. AngularJS comes with a service called $anchorScroll that can be used to emulate the browser's hash-based positioning we're familiar with. You could obviously also use a jQuery plugin to animate the scrolling if you wanted to.
And that's it! A very simply directive, a fairly simple service, and whatever trigger(s) you need. All told, I'd guess less than 100 lines of code including tests. All components are decoupled and easily testable, but still really quite simple. The view remains The Truth. The Angular Way is preserved.
And there was much rejoicing.
I hope this sets you on the right direction, but of course feel free to ask a follow-up question. We can also talk code specifics too if you'd like; as I said, they wouldn't be very complicated.
AngularJS services are singletons and can be required via dependency injection. You could have your directives require a state manager service and call incrementers/decrementers.
Alternatively, a little easier but more brittle, you could keep an array in $rootScope. It's more idiomatic "angular" (but not by much) than a jquery selector global, but probably not the best route if you're building a widget library.

What is the difference between facelets's ui:include and custom tag?

Ui:include and xhtml based tag (the one with source elt) seem to be much the same for me. Both allow to reuse piece of markup. But I believe there should be some reason for having each. Could somebody please briefly explain it? (I guess if I read full facelets tutorial I will learn it, but I have not time to do it now, so no links to lengthy docs please :)
They are quite similar. The difference is mainly syntactical.
After observing their usage for some time it seems the convention is that fragments that you use only in a single situation are candidates for ui:include, while fragments that you re-use more often and have a more independent semantic are candidates for a custom tag.
E.g.
A single view might have a form with three sections; personal data, work history, preferences. If the page becomes unwieldy, you can divide it into smaller parts. Each of the 3 sections could be moved to their own Facelet file and will then be ui-include'ed into the original file.
On the other hand, you might have a specific way to display on image on many views in your application. Maybe you draw a line around it, have some text beneath it etc. Instead of repeating this over and over again you can abstract this to its own Facelet file again. Although you could ui:include it, most people seem to prefer to create a tag here, so you can use e.g. <my:image src="..." /> on your Facelets. This just looks nicer (more compact, more inline with other components).
In the Facelets version that's bundled with JSF 2.0, simple tags can be replaced by composite components. This is yet a third variant that on the first glance looks a lot like custom tags, but these things are technically different as they aren't merely an include but represent true components with declared attributes, ability to attach validators to, etc.

Resources