I totally hate to add tag names based on component names in my apps. I hate to do this:
<hero-detail hero="ctrl.hero"></hero-detail>
Isn’t it possible to use normal div tags instead? Something like this?
<div id="hero-detail" data-hero="ctrl.hero"></div>
why isn’t that working?
You can technically restrict a component to an attribute as you do with directives since components are a special kind of directive. (I modified a random fiddle found on google)
EDIT: this does work on older 1.5 versions but not on newer ones. So read on...
But officially you cannot and you shouldn't do it anyway. If you choose a component architecture, you have to stick to the rules or things will get out of hands quickly.
Having components as html elements is clean and good practice. You should learn to like it.
why not, that is also possible.
basically in three ways we can specify the directives.
i.e Element, Attribute, Classname
but while create the directive you can specify
restriction : AE
or whaterver you need,
then you can use like this
<div id="hero-detail" hero-detail data-hero="ctrl.hero"></div>
for more have a deep look at the docs. directives
your answer is here https://docs.angularjs.org/guide/directive
They says:
Directive types $compile can match directives based on element names,
attributes, class names, as well as comments.
All of the Angular-provided directives match attribute name, tag name,
comments, or class name. The following demonstrates the various ways a
directive (myDir in this case) can be referenced from within a
template:
<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>
Best Practice: Prefer using directives via tag name and attributes
over comment and class names. Doing so generally makes it easier to
determine what directives a given element matches.
Best Practice: Comment directives were commonly used in places where
the DOM API limits the ability to create directives that spanned
multiple elements (e.g. inside elements). AngularJS 1.2
introduces ng-repeat-start and ng-repeat-end as a better solution to
this problem. Developers are encouraged to use this over custom
comment directives when possible.
Related
Say, if you define a directive with the template:
<div>
<button id="add-button">add</button>
{{ value }}
<button id="minus-button">minus</button>
</div>
Then what is a correct way to find your button in your link(scope, element, attrs) function?
Some thoughts and details:
I have seen
angular.element(document.getElementById("add-button"))
(the angular.element is just to convert it back to a jqLite/jQuery object)
but what if a user adds your directives multiple times on their page, then that line will find the wrong element because document.getElementById("add-button") will probably find the first matching element on the whole page with that ID.
Since jqLite can only find by tag name, so we may be able to do, by going back to DOM methods:
angular.element(element[0].querySelector("#add-button"))
Or, I don't know why jqLite doesn't let you find by class name or by ID, so it may be recommended to actually load jQuery before AngularJS, and use the full version of jQuery:
element.find("#add-button")
Or, supposedly only one element with the same ID should exist on the whole page, so to be more correct, we really should use class name instead of ID to identify the element, such as <button class="add-button"> and find it by
element.find(".add-button")
I think searching by tag name and then using the 1st found element or 2nd found element is not such a good way, because what if the template is changed or rearranged later, then you need to change your code too, so it is too tightly coupled together.
The most common way (seen by John Papa and Todd Motto) is to go with jqLite.
The worst way is using JQuery inside directives without restrictions.
Absolutly worst case:
$('.some-class')
Much better:
element.find('.some-class')
Also seen and valid:
$(element.find('.some-class'))
So, why you gonna do such things, manipulating DOM from a directive? There are a whole bunch of reasons. Maybe you want to initialize some JQuery plugins like datepicker or nanoscroller, then you need such things.
Styleguides are just philosphy, you can accept them, you just believe in small parts of the whole guide or you create your own. There are some guidelines out there, which can improve your code heavily (performance, readablity, etc.).
Styleguides
Angular 2 John Papa
Angular 1.x John Papa
Angular 1.x Todd Motto
This question already has an answer here:
Do I still need to use data-ng with AngularJS or can I drop the data-?
(1 answer)
Closed 8 years ago.
I've come to know that data-ng-* is validation-friendly. But I've come across many places where I see snippets having ng-* over data-ng-*. Even the snippets in the angular official sites. Why is it so?
To embed custom non visible data we use data-. hence using data-ng- is suggested instead of ng-app To make it a valid html template.
Please refer : W3C
From the HTML 5.1 Editor's Draft,
3.2.5.9 Embedding custom non-visible data with the data-* attributes
A custom data attribute is an attribute in no namespace whose name
starts with the string "data-", has at least one character after the
hyphen, is
XML-compatible,
and contains no uppercase ASCII
letters.
And the official angularjs documentation:
What are Directives?
At a high level, directives are markers on a DOM element (such as an
attribute, element name, comment or CSS class) that tell AngularJS's
HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.
Angular comes with a set of these directives built-in, like ngBind,
ngModel, and ngClass. Much like you create controllers and
services, you can create your own directives for Angular to use. When
Angular bootstraps your
application, the HTML
compiler traverses the DOM
matching directives against the DOM elements.
And farther down the page:
Best Practice: Prefer using the dash-delimited format (e.g. ng-bind for ngBind). If you want to use an HTML validating tool,
you can instead use the data-prefixed version (e.g. data-ng-bind
for ngBind). The other forms shown above are accepted for legacy
reasons but we advise you to avoid them.
So directives of the form data-ng-* are only necessary if you want your HTML to validate. Otherwise, it's "deprecated". Use ng-* instead.
Assuming that a Custom Directive:
define a custom tag or attribute that is expanded or replaced
can include Controller logic, if needed
and that the Directive can be of type Element
<my-customdirective></my-customdirective>
or of type Attribute
<h4 my-customdirective></h4>
my question is WHEN and WHY I decide to use one rather than another?
Quoted from the documentation:
When should I use an attribute versus an element? Use an element when
you are creating a component that is in control of the template. The
common case for this is when you are creating a Domain-Specific
Language for parts of your template. Use an attribute when you are
decorating an existing element with new functionality.
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.
For More Details
A simple example to explain my case:
I have a directive for labels
<input label="{{obj.label}}"/>
But for some other directives I want to use an attribute with name "label"
<other-directive label="My label"></other-directive>
just as an attribute, not processing the label-directive.
I could just rename the attribute to e.g. "my-label":
<other-directive my-label="My label"></other-directive>
but it would be nice to use "label" as an attribute name.
As #ExpertSystem points out in the comments to the question, angular really has no way of knowing out of the box whether your directive should be applied in one case versus another. The only way I can think of to get around this is to include logic in your directive's compile function that knows how to determine whether it should be applied or not. This plunker demonstrates how I would accomplish this. You basically need to return two different link functions from the compilation phase; one if your directive should be applied (in this case adding a label before the input), and a different one if it should be skipped. You are then free to use that as an argument to a separate directive. This may not work if your directive needs to do things like transclusion or isolated scopes (things that angular doesn't like two directives on the same element to do).
I'd be very sparing with how you use this, however, as it will create an inconsistent API for other developers who may be working with this code. They may not know when the directive will apply and when it won't.
Egghead.io has a great explanation of directive restrictions in AngularJS. A custom directive can be defined as follows:
angular.module("app", []).directive("blah", function () {
return {
restrict: "A",
template: "blah directive. nothing to see here."
};
});
This creates a what I will call an attribute directive (due to restrict: "A") for the purposes of asking this question. This is actually Angular's default restriction on a custom directive, and this directive can be used like:
<div blah>
<!-- content of directive -->
</div>
When I want to create a custom directive, however, I normally go for an element directive, like:
<blah>
<!-- content of directive -->
</blah>
How is the former attribute directive any better than the latter element directive and why was it chosen as the default?
This is my opinion, only:
There are three possible ways to define a directive in the HTML - attributes, elements and classes. Classes are too lax and confusing, and a best practice would be to separate logic from style. Element directives are too strict - you can only have one "element" directive in a DOM element. That makes them special right from the start.
An attribute seems to be the best middle ground between these two extremes - it is clear, allows for multiple directives in an element (If you are following Egghead's videos, the superhero example on "directive to directive communication" shows a kind of "directive hierarchy", elements superseding attributes. Also, and this is very important most of the times (I program for intranet apps, so to me it isn't) attributes allow angularJS templates to be valid HTML.
EDIT - my two cents would be that it doesn't matter - in any real scenario, it is a bad idea to trust the "default" configuration of something as primary as the restrict option - setting it explicitly makes for clear, no doubt directives (especially working in team projects, but also anytime, really)
Angular 1.3 changed the default to be 'AE'. See: https://docs.angularjs.org/api/ng/service/$compile#directive-definition-object.
I'm guessing it was changed because it's "restrict", not "include". So, the default for "restrict" should restrict very little.
What does that mean going forward -- if you see a "restrict: 'E'" line, it actually means "This wasn't meant to be used as an attribute", rather than the potential current meaning of "I simply want to use this as an element".
My take on this would be:
An element-based directive would most often represent structural functionality.
For instance, I use element-based directives for popups, dialogs, tabbed widgets, and reusable widgets in general. I then can add attribute-based directives to them (say, adding an ng-click to a <ui-button> directive), but the element name (i.e. the directive name) represents the structural semantics of what is being built.