AngularJS deeply learns how to use commands in the angularjs framework of JavaScript.

Source: Internet
Author: User

AngularJS deeply learns how to use commands in the angularjs framework of JavaScript.

Directive is the most important part of all AngularJS applications. Although AngularJS already provides a rich set of commands, you often need to create application-specific commands. This tutorial will show you how to customize commands and how to use them in real projects. At the end of this article (Part 2), I will guide you how to use the Angular command to create a simple notepad application.

Overview

A command is used to introduce new HTML syntax. A command is a tag on a DOM element that gives the element specific behavior. For example, static HTML does not know how to create and display a date selector control. For HTML to recognize this syntax, we need to use instructions. Command to create an element that supports date Selection in some way. We will explain how this is implemented step by step. If you have written AngularJS applications, you must have used commands no matter whether you have realized them. You must have used simple commands, such as ng-mode, ng-repeat, and ng-show. These commands give specific actions to the DOM element. For example, ng-repeat repeats a specific element and ng-show displays an element conditionally. If you want to drag an element, you also need to create a command to implement it. The basic idea behind commands is simple. It listens to element binding events or changes DOM to make HTML have real interaction.

JQuery perspective

Imagine how to create a date selector using jQuery. First, we add a common input box in HTML and call $ (element). dataPicker () through jQuery to convert it into a date selector. But think about it. When a designer checks the HTML Tag, can he/she immediately guess what the field actually represents? Is this just a simple input box or a date selector? You need to check the jQuery code to determine this. Angular uses an instruction to expand HTML. Therefore, a date selector instruction can be in the following format:

<input type="text" />

Or:

<input type="text" />


This method of creating a UI is more direct and clear. You can easily see what the elements are.

Create custom commands:

An Angular command can be expressed in the following four forms: 1. A new HTML element (<data-picker> </data-picker>) 2. element attributes (<input type = "text" data-picker/>) 3. CSS class (<input type = "text" class = "data-picker"/>) 4. note (<! -Directive: data-picker->) Of course, we can control the representation of our commands in HTML. Next, let's take a look at the typical instructions in AngularJS. Command registration is the same as controller, But it returns a simple object (command definition object) with the command configuration attributes ). The following code is a simple Hello World command.

var app = angular.module('myapp', []); app.directive('helloWorld', function() { return {   restrict: 'AE',   replace: 'true',   template: '

In the above Code, the app. directive () method registers a new instruction in the module. The first parameter of this method is the name of this command. The second parameter is a function that returns a command to define an object. If your commands depend on other objects or services, such as $ rootScope, $ http, or $ compile, they can be injected at this time. This command is used as an element in HTML, as follows:

Alternatively, use the following attributes:

<div hello-world></div>//OR<div hello:world/>

If you want to comply with HTML5 specifications, you can add the x-or data-Prefix before the element. Therefore, the following mark will also match the helloWorld command:

<div data-hello-world></div>//OR<div x-hello-world></div>

Note: When matching commands, Angular removes the x-or data-Prefix from element or attribute names. Then, convert the-or: connected string to the camelCase representation and match it with the registered command. This is why we use the helloWorld command in the form of hello-world in HTML. In fact, this is related to the fact that HTML is not case sensitive to tags and attributes. Although the above commands only display static text, there are some interesting points worth exploring. Three attributes are used to configure commands during instruction definition. Let's introduce their functions one by one.

  • Restrict-this attribute is used to specify how commands are used in HTML (remember the four Representation Methods of commands mentioned earlier ). In the above example, we use 'AE '. Therefore, this command can be used as a new HTML element or attribute. If you want to allow the command to be used as a class, Set restrict to 'aec '.
  • Template-this attribute specifies the HTML Tag generated after the command is compiled by Angular and linked. This attribute value is not necessarily a simple string. Templates can be very complex and often contain other commands and expressions. In more cases, you may see templateUrl instead of template. Therefore, ideally, you should place the template in a specific HTML file and point the templateUrl attribute to it.
  • Replace-this attribute indicates whether the generated HTML content will replace the HTML element defining this instruction. In our example, we use the

Open this plunker and click "Hello World !!" Right-click the element content to better understand it.

Link Function and Scope

The template generated by the command does not make much sense unless it is compiled under a specific scope. By default, the command does not create a new sub-scope. More, it uses the parent scope. That is to say, if the command exists in a controller, it will use the scope of the controller. To use scope, we need to use a function called link. It is configured by the link attribute in the instruction definition object. Let's change our helloWorld command. When a user enters a color name in an input box, the background color of the Hello World text changes automatically. At the same time, when the user clicks on the Hello World text, the background color becomes white. The corresponding HTML Tag is as follows:

<body ng-controller="MainCtrl"> <input type="text" ng-model="color" placeholder="Enter a color" /> 

The modified helloWorld command is as follows:

app.directive('helloWorld', function() { return {  restrict: 'AE',  replace: true,  template: '<p style="background-color:{{color}}">Hello World',  link: function(scope, elem, attrs) {   elem.bind('click', function() {    elem.css('background-color', 'white');    scope.$apply(function() {     scope.color = "white";    });   });   elem.bind('mouseover', function() {    elem.css('cursor', 'pointer');   });  } };});

We noticed the link function in the instruction definition. It has three parameters:

  • Scope-command scope. In our example, the scope of the command is the scope of the parent controller.
  • The jQLite (subset of jQuery) of the elem-Directive wraps DOM elements. If you have introduced jQuery before AngularJS, this element is a jQuery element, not a jQLite element. Since this element has been packaged by jQuery/jQLite, we don't need to use $ () For DOM operations.
  • Attr-a standardized parameter object that contains the attributes of the element where the instruction is located. For example, if you add some attributes to an HTML element: You can use it in the link function through attrs. someAttribute.

The link function is used to add event listening to DOM elements, monitor model attribute changes, and update DOM. In the preceding command code snippet, we added two events, click, and mouseover. The click handler is used to reset the background color of <p>, while the mouseover handler changes the mouse to pointer. There is an expression {color} in the template. When the color in the parent scope changes, it is used to change the background color of the Hello World text. This plunker demonstrates these concepts.

Compile Functions

The compile function is used for DOM transformation before the link function is executed. It receives the following parameters:

TElement-element of the Instruction
Attrs-Standardization List of parameters granted on the element
Note that the compile function cannot access the scope and must return a link function. However, if the compile function is not set, you can configure the link function normally. (With compile, you cannot use link. The link function is returned by compile ). The compile function can be written as follows:

app.directive('test', function() { return {  compile: function(tElem,attrs) {   //do optional DOM transformation here   return function(scope,elem,attrs) {    //linking function here   };  } };});

In most cases, you only need to use the link function. This is because most of the commands only need to consider registering event listening, monitoring models, and updating DOM, which can be completed in the link function. However, for commands such as ng-repeat, the DOM elements need to be cloned and repeated multiple times. The compile function is used to complete the tasks before the link function is executed. This raises a question. Why can't we use only one function if we need two separate functions to complete the generation process? To answer this question, we need to understand how commands are compiled in Angular!

How commands are compiled

When the application is started, Angular starts to use the $ compile service to traverse DOM elements. This service searches for commands in the markup text based on the registered commands. Angular executes their compile method once all commands are identified. As mentioned above, the compile method returns a link function and is added to the list of link functions executed later. This is called the compilation phase. If a command needs to be cloned many times (for example, ng-repeat), the compile function is executed only once during the compilation phase. Copy these templates, however, the link function is executed for each copied instance. Therefore, separate processing improves the performance. This also explains why the scope object cannot be accessed in the compile function. After the compilation phase, the linking phase is started. At this stage, all the collected link functions will be executed one by one. Templates created by commands are parsed and processed in the correct scope, and real DOM nodes with event responses are returned.

Change the Scope of the command

By default, the command gets the scope of the controller of its parent node. However, this does not apply to all situations. If you expose the scope of the parent controller to the instruction, they can modify the attributes of the scope at will. In some cases, you want to add internal-only attributes and methods. If we add the parent scope, the parent scope will be contaminated. In fact, we have two options:

A sub-scope-this scope prototype inherits the sub-parent scope.
An isolated scope-an exclusive scope that does not inherit from the parent scope.
Such a scope can be configured by defining the scope attribute in the object through commands. The following code snippet is an example:

app.directive('helloWorld', function() { return {  scope: true, // use a child scope that inherits from parent  restrict: 'AE',  replace: 'true',  template: '

The code above allows Angular to create a new sub-scope inherited from the parent socpe for the command. Another option is to isolate the scope:

app.directive('helloWorld', function() { return {  scope: {}, // use a new isolated scope  restrict: 'AE',  replace: 'true',  template: '

This command uses an isolated scope. The isolated scope is very advantageous when we want to create reusable commands. By using an isolated scope, we can ensure that our commands are self-contained and can be easily inserted into HTML applications. It cannot access the parent scope internally and ensures that the parent scope is not contaminated. In our helloWorld command example, if we set scope to {}, the above Code will not work. It will create a new isolated scope, and the corresponding expression {color} will point to this new scope, and its value will be undefined. using an isolated scope does not mean that we cannot access the attributes of the parent scope at all.

Isolate data binding between scope and parent scope

Generally, the scope of the isolation command brings a lot of convenience, especially when you want to operate multiple scope models. But sometimes in order to make the code work correctly, you also need to access the attributes of the parent scope from within the instruction. The good news is that Angular gives you enough flexibility to selectively pass in attributes of the parent scope through binding. Let's review our helloWorld command. Its background color changes with the color name entered in the input box. Remember when we use an isolated scope for this command, it will not work anymore? Now let's restore it to normal.

Suppose we have initialized the Angular module pointed to by the app variable. The following code shows the helloWorld command:

app.directive('helloWorld', function() { return {  scope: {},  restrict: 'AE',  replace: true,  template: '<p style="background-color:{{color}}">Hello World</p>',  link: function(scope, elem, attrs) {   elem.bind('click', function() {    elem.css('background-color','white');    scope.$apply(function() {     scope.color = "white";    });   });   elem.bind('mouseover', function() {    elem.css('cursor', 'pointer');   });  } };});

The HTML Tag using this command is as follows:

<body ng-controller="MainCtrl"> <input type="text" ng-model="color" placeholder="Enter a color"/> 

The above Code cannot work now. Because we use an isolated scope, the {color} expressions in the instruction are isolated from the scope (not the parent scope) in the instruction ). However, the ng-model command in the input box element points to the color attribute in the parent scope. Therefore, we need to bind the two parameters in the isolation scope and parent scope. In Angular, this type of data binding can be achieved by adding attributes to the HTML element where the directive is located and configuring the corresponding scope attributes in the directive definition object. Let's take a closer look at several data binding methods.

Option 1: Use @ to bind one-way text

In the following command definition, we specify the colorAttr parameter for binding the attribute color in the isolated scope to the HTML element of the instruction. In the HTML Tag, you can see that the {color} expression is specified to the color-attr parameter. When the expression value changes, the color-attr parameter also changes. The value of the color attribute in the quarantine scope is also changed.

app.directive('helloWorld', function() { return {  scope: {   color: '@colorAttr'  },  ....  // the rest of the configurations };});

The updated HTML Tag code is as follows:

<body ng-controller="MainCtrl"> <input type="text" ng-model="color" placeholder="Enter a color"/> 

This method is called single-item binding because in this method, you can only pass strings (using expressions {{}}) to parameters. When the attributes of the parent scope change, the attribute values in your isolated scope model change. You can even monitor the changes to the scope attribute inside the command and trigger some tasks. However, reverse transfer does not work. You cannot change the value of the parent scope by operating the isolate scope attribute.

Note:
When the isolation scope attribute is the same as the command element parameter name, you can set scope binding in a simpler way:

app.directive('helloWorld', function() { return {  scope: {   color: '@'  },  ....  // the rest of the configurations };});

The HTML code of the corresponding instruction is as follows:

Option 2: Use = to implement bidirectional binding

Let's change the definition of the command to the following:

app.directive('helloWorld', function() { return {  scope: {   color: '='  },  ....  // the rest of the configurations };});

The corresponding HTML modification is as follows:

<body ng-controller="MainCtrl"> <input type="text" ng-model="color" placeholder="Enter a color"/> 

Unlike @, This method allows you to specify a real scope data model for attributes, rather than a simple string. In this way, you can pass simple strings, arrays, and even complex objects to the isolated scope. Two-way binding is also supported. When the parent scope attribute changes, the attribute in the corresponding isolated scope also changes, and vice versa. As before, you can also monitor the changes to this scope attribute.

Select 3: Use & execute the function in the parent scope

Sometimes it is necessary to call the functions defined in the parent scope from the isolated scope. To access the functions defined in the external scope, we use &. For example, we want to call the sayHello () method from inside the command. The following code tells us how to do this:

app.directive('sayHello', function() { return {  scope: {   sayHelloIsolated: '&'  },  ....  // the rest of the configurations };});

The corresponding HTML code is as follows:

<body ng-controller="MainCtrl"> <input type="text" ng-model="color" placeholder="Enter a color"/> <say-hello sayHelloIsolated="sayHello()"/></body>

This Plunker example provides a good explanation of the above concepts.

Differences between parent scope, subscope, and isolated scope

As a newbie to Angular, you may be confused when choosing the correct command scope. By default, the command does not create a new scope, but follows the parent scope. But in many cases, this is not what we want. If your command heavily uses the attributes of the parent scope, or even creates new attributes, parent scope will be contaminated. It is not a good idea to allow all commands to use the same parent scope, because anyone may modify the attributes in this scope. Therefore, the following principle may help you select the correct scope for your instructions.

1. Parent scope (scope: false)-this is the default situation. If your command does not operate the attributes of the parent scoe, you do not need a new scope. In this case, the parent scope can be used.

2. Sub-scope (scope: true)-This creates a new scope for the instruction and the prototype inherits from the parent scope. If the attributes and methods in your instruction scope have no relationship with other instructions and the parent scope, you should create a new scope. In this way, you also have the attributes and methods defined in the parent scope.

3. Isolate scope (scope :{})-This is like a sandbox! When the commands you create are self-contained and reusable, you need to use this scope. You will create many scope attributes and methods in the command. They are only used inside the command and will never be known to the outside world. If so, the isolated scope is a better choice. The isolated scope does not inherit the parent scope.

Transclusion (embedded)

Transclusion is a method that allows our commands to contain arbitrary content. We can extract the embedded content in a delayed manner and compile the embedded content in the correct scope, and finally put them into the location specified in the instruction template. If you set transclude: true in the Command definition, a new embedded scope will be created, and its prototype inherits the sub-parent scope. If you want your command to use an isolated scope, but the content contained in it can be executed in the parent scope, transclusion can also help.

Suppose we register the following command:

app.directive('outputText', function() { return {  transclude: true,  scope: {},  template: '<div ng-transclude></div>' };});

It uses the following:

<div output-text> <p>Hello {{name}}</p></div>

Ng-transclude indicates where the content is embedded. In this example, the DOM content <p> Hello {name }}</p> is extracted and placed inside <div ng-transclude> </div>. It is important to note that the attribute of the expression {name} is defined in the parent scope, rather than the subscope. You can do some experiments in this Plunker example. If you want to learn

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.