Directives are one of the techniques we use to extend browser capabilities. During DOM compilation, the instructions associated with the HTML element are detected and executed. This allows the instruction to specify the behavior for the DOM, or to change it.
Angularjs has a complete and extensible set of instructions to help Web application development, which enables HTML to be transformed into a "domain-specific language (DSL)".
Directives can be used as element names, attribute names, class names, or annotations in HTML. Here are some examples of equivalent invocation of the MYDIR directive:
<span my-dir= "exp" ></span><span class= "MY-DIR:EXP;" ></span><my-dir></my-dir><!--directive:my-dir Exp---
Angular during compilation, the compiler uses the $interpolate service to check whether the expression is embedded in the text. This expression is registered as a monitor and is automatically updated as part of the $digest loop.
The compilation of HTML is divided into three phases:
-
The browser will first parse HTML into the DOM using its standard API. You need to recognize this because our templates must be HTML that can be parsed. This is the difference between Angularjs and those "string-based rather than DOM-based" templating systems. The compilation of the
-
Dom is performed by the method. This method iterates through the DOM and finds the matching instructions. Once found, it is added to a list of instructions, which is used to record all instructions related to the current DOM. Once all the instructions have been determined, they are sorted by priority, and their compile
method is called. The $compile ()
function modifies the DOM structure and is responsible for generating a link function (which is mentioned later). The $compile method finally returns a merged link function, which is the collection of linked functions returned by the compile function of each instruction.
-
Links the template to the scope by calling the link function that was described in the previous step. This turns on the link function for each instruction, allowing each instruction to register the listener for the DOM and establish the scope of the listener. This finally forms the dynamic binding of the scoped DOM. Any change in scope will be reflected in the DOM.
var html = ' <div ng-bind= ' exp ' ></div> '; // Step 1:parse HTML into DOM element var template = angular.element (HTML); // Step 2:compile the template var linkfn = $compile (template); // Step 3:link The compiled template with the scope. LINKFN (scope);
You may wonder why the compilation process and the linking process are separated. To understand why, you can first look at the following example with a "Repeat command":
Hello {{User}}, you have these actions:<ul> <li ng-repeat= ' action in user.actions ' > { {action.description}} </li></ul>
When the above example is compiled, the compiler will traverse all nodes to look for instructions. For example {{user}} is a replacement instruction, Ngrepeat is another directive. But Ngrepeat has a problem. He needs to construct an Li for each action in the user.actions. This means that it first saves a "clean" li element as a clone, and then, when the new action is inserted, clones the clean Li element and inserts the cloned Li element into the UL. But the work is not over just cloning Li. He also needs to compile the Li to replace the substitution of {{action.descriptions}} with the value under the corresponding scope. We can use an easy way to clone and insert an LI element, and then compile it. But to compile each Li Word, the speed is very slow, because the compiled project requires us to traverse the DOM tree. If we perform the compilation in a loop that requires 100 loops, the performance problem is immediately apparent.
And our solution is to divide the compilation project into two stages. The compile phase identifies the directives and sorts them by priority, linking the instances in the scope to the Li in the link stage.
Ngrepeat will block the compilation of the Li child element {{action.description}}, instead the ngrepeat instruction will compile the Li separately, and at compile time, a template consisting of several Li elements will be generated. This compilation ends with a link function that, when executed, compiles the entire template, creates a new scope for each Li element, and links it to the corresponding scope. Here, we only need to compile once (a uniform compilation of the template is all right), but only when the link is linked multiple times, and the link operation does not consume performance.
How to write an instruction
varMyModule =angular.module (...); Mymodule.directive (' Directivename ',functionFactory (injectables) {varDirectivedefinitionobject ={priority:0, Template:' <div></div> ', Templateurl:' Directive.html ', replace:false, transclude:false, restrict:A, Scope:false, compile:functioncompile (telement, Tattrs, transclude) {return{pre:functionprelink (Scope, ielement, Iattrs, controller) {...}, post:functionPostlink (Scope, ielement, Iattrs, controller) {...} }}, Link:functionPostlink (Scope, ielement, Iattrs) {...} }; returnDirectivedefinitionobject;});
In most cases you don't need to control so much detail, to simplify the code above, we first need to rely on the default value of the basic option. If you use the default values, the above code can be simplified to:
var mymodule = angular.module (...); Mymodule.directive (function Factory (injectables) { var Directivedefinitionobject = { function compile (telement, tattrs) { return function postlink (scope, ielement, Iattrs) {...}} ; return Directivedefinitionobject;});
Since most of the instructions only care about the instance, there is no need to deform the template, so we can also simplify it to:
var mymodule = angular.module (...); Mymodule.directive (function Factory (injectables) { returnfunction Postlink (Scope, ielement, Iattrs) {...}});
The factory function in the above code, we call the factory function, it is used to create instructions. It will only be called once: when the compiler first matches the corresponding instruction, you can do any initialization work in it. It is used when calling it $injector.invoke
, so it follows all the rules of the injector.
The directive definition object, the Directivedefinitionobject object in the code above, gives the compiler the details needed to generate the instructions. The properties of this object are:
Name-name of the current scope.
Precedence priority-when there are multiple instructions on a DOM, you will need to specify the order in which the instructions are executed. This priority is used to sort the compile function before executing the instruction. High-priority execution first.
Terminal-If set to true, then the instruction is finally executed in the same DOM's instruction set.
Scope scope-If it is defined as:
True-then a new scope is created for the current instruction. If there are multiple instructions on the same DOM that require a new scope to be created, only a new one will be created. This rule that creates a new scope does not apply to the root node of the template, because the root node of the template always gets a new scope.
{}, Object hash-then a new "orphaned" Scope is created. This "orphaned" scope differs from the general scope in that it does not inherit directly from the parent scope in the form of a prototype inheritance. This is useful for creating reusable components, because reusable components should generally not read or write data from the parent scope. This "orphaned" Scope uses an object, hash, that defines a series of local scope properties that can be used in the following ways.
- The
-
@ or @attr -binds local scope members and Dom properties. The binding result is always a string, because the DOM property is a string. What is the difference between the @ and the @attr? For example: @ Way: <widget flater= "Hello {{name}}";
and scope objects: {flater: ' @ '}
. When the DOM property Flater name
value changes, the Flater in the scope also changes, Because the local scope member Flater binds the DOM property of this Directive widget Flater, and the DOM property Flater name the value
is read from the parent scope, This means that the parent scope has the Name property. @attr Way: <widget my-attr= "Hello {{name}}";
and scope objects: {localname: ' @myAttr '}
. When the name
value changes, the LocalName in the scope also changes. It is characterized by the parent scope passing a property to the child scope.
= or =expression-establishes a two-way binding between the local scope property and the parent scope property. = Way: <widget flater="parentModel">
and scope object: { flater:‘=‘ }
The local property flater reflects the values in the parent scope, and parentModel
any change in Flater and Parentmodel affects the other, and the principle is that the Flater is the property of the child scope, Parentmodel are properties of the parent scope, they are bound in two directions, one side is changed, the other is changed, and they are linked by Dom attribute Flater. =expression: <widget my-attr="parentModel">
and scope object: { localModel:‘=myAttr‘ }
The local property localModel
reflects parentModel
the value in the parent scope. Its characteristics: the properties under the parent scope are bound to two-way with the properties under the sub-scope.
& or &attr-for example: <widget flater= "SayHello (name)" > and scope objects: {flater: ' & '}, The local property Flater binds the SayHello method under the parent scope. At this point, your Flater method in the sub-scope is actually called the SayHello method under the parent scope. If a parameter is required, it is passed Flater ({name: "Chaojidan"}). It features: The parent scope passes a function to the child scope.
Controller-This is the controller inside the directive, unlike the controller in angular. Its role is to expose some methods of this instruction to other instructions to use. This controller function is executed during the pre-compilation phase, and it is shared, which allows the instructions to communicate with each other to expand their capabilities.
Require-the request takes another instruction, assuming that the internal controller in Direct2 is passed as a parameter to the link function of the current instruction, so that in the link function of the current instruction, You can invoke the method defined in the internal controller in the DIRECT2 directive. This request needs to pass the name of the requested instruction. If it is not found, an error is triggered. The name of the request can be prefixed with the following two prefixes:
?
-Do not trigger an error, this is just an optional request.
^
-If not found, in the scope of the parent element to find there is no.
-
Restrict -Any one of the letters in the EACM. It is used to restrict the declaration format of an instruction. If there is no such item. That only allows the use of directives in the form of attributes.
- E-element name:
<MY-DIRECTIVE></MY-DIRECTIVE>
- A-Properties: &nbs P
<div my-directive= "exp" > </div>
- C-Class name:
<div class= "MY-DIRECTIVE:EXP;" ></div>
- M-Note:
<!--directive:my-directive exp-->
模板template
-Replaces the current element. This substitution process automatically adds the attributes of the element and the CSS class name to the new element.
Template address Templateurl-the same as the template property, except that this indicates the URL of a profile. Because template loading is asynchronous, all compilations and links will wait until the load is complete before executing.
Replace replacement-If set to true, content inside the instruction inside the page will be replaced by the template. For example:
Transclude-If you do not want content inside the instruction to be replaced by a template, you can set this value to true. In general, it needs to be used in conjunction with the Ngtransclude directive. For example: Template: "<div>hello every <div ng-transclude></div></div>", at this time, The content inside the instruction is embedded in the ng-transclude Div. It becomes the <div>hello every <div> this is the internal content of the directive </div></div>
Compile compile-This is the compiler function that will be discussed later.
- Link-This is the link function that will be discussed later.
Compiler functions Compile function
function Compile (telement, Tattrs, transclude) {...}
The compile function is used to handle situations where the template DOM needs to be modified. Because most instructions do not need to modify the template, this function is not commonly used. Examples that need to be used are the ngTrepeat
need to modify the template, and the need to load the ngView
content asynchronously. The compilation function accepts the following parameters.
telement-template element-The elements in which the directive resides. It is safe to deform such an element and its child elements.
Tattrs-template attributes-attributes of all directives declared on this element, which are shared in the compilation function.
transclude-an embedded link function function(scope, cloneLinkingFn)
.
Note: Do not perform any operations outside of the DOM transformation in the compilation function. More importantly, the registration of DOM listener events should be done in the link function, not in the compilation function.
A compilation function can return an object or function.
Return function-is equivalent to a link function that is registered with the properties of the Configuration object when the compilation function does not exist link
.
Return object-Returns an pre
post
object that is registered with a function or property. Refer pre-linking
post-liking
to the explanations below and functions.
Link functions linking function
function Link (scope, ielement, Iattrs, controller) {...}
The link function is responsible for registering DOM events and updating the DOM. It is executed after the template has been cloned, and it is also where most of the instruction logic code is written.
Scope-the scope in which the instruction needs to be monitored.
ielement-instance element-The elements in which the directive resides. postLink
It is only safe to operate on the child elements of the element in the function, because they are all linked at that time.
Iattrs-instance attributes-instance properties, a normalized, all attribute list declared on the current element, which is shared across all linked functions.
Controller-An instance of the director, which is the current instruction direct2 the internal controller through the instruction of the require request. For example: Controller:function () {this.addstrength = function () {}} in the DIRECT2 directive, then, in the link function of the current instruction, You can make the call through Controller.addstrength.
The Pre-linking function executes before the child element is linked. cannot be used to deform the DOM in case the link function cannot find the correct element to link to.
post-linking function all elements are linked and executed.
Property Attributes
The Attributes object property-passed as a parameter to the link function and the compilation function. This allows the following resources to be used.
-
Normalized property name: Because the name of the directive, such as ngbind
, can be represented in many variants, such as ng:bind
, or x-ng-bind
, which makes it possible to obtain the corresponding property with a standard name.
-
Inter-Directive communication: All instructions share an instance of the same Property object, which allows the instruction to communicate through this Property object.
-
Supports substitution: If a property contains a substitution, other instructions can read the value of the substitution.
-
Monitors for substituted properties: Using $observe, you can monitor properties that use substitutions (such as src= "{{bar}}"
). This is an efficient and unique way to get the value of a variable. Since the link phase substitution has not been replaced with a value, all variables are undefined at this time.
function LINKINGFN (Scope, Elm, Attrs, ctrl) { // Get the attribute value console.log (Attrs.ngmo DEL); // Change the attribute attrs. $set (' Ngmodel ', ' new value '); // observe changes to interpolated attributefunction(value) { Console.log (' Ngmodel have changed value to ' + value); }); }
Creating components
It is often necessary to replace a single instruction with a more complex DOM structure. This allows the directive to become a short flag that can generate reusable components of an application.
Come on!
ANGULARJS Development Guide 4: An explanation of the instructions