When it comes to AngularJS, the first thing we think of is probably two-way data binding and instruction system, which are also the most attractive aspects of AngularJS. As for two-way data binding, I feel that there is nothing to say. So today we will briefly discuss the instruction system of the AngularJS framework. I am also a beginner and have consulted some information. If there are some bad things, Wan Wang pointed it out.
Directives are the most important part of AngularJS, so this framework itself comes with more instructions, but in development, these instructions usually cannot meet our needs, so we also need to customize some instructions. Then an AngularJS directive can have four forms of expression in HTML code:
1. Use as a new HTML element.
<hello></hello> or <hello/>
2. Use as an attribute of an element
<div hello></div>
3. Use as an element class
<div></div>
4. Use as comments
<!--directive: hello -->
Note that there is a trap here, which is to have a space after "directive: hello", otherwise it will be useless. At the same time, it is recommended to use less annotation methods. If you have to pursue high quality, then be casual. Since the instructions have the above four forms of expression, how do they define them specifically?
.directive('hello',function(){ return { restrict:'AECM', template:'<button>click me</button>' } })The above is the simplest code to define a directive, no doubt about it. In the above code, the directive() method defines a new instruction. The method has two parameters. The first 'hello' is to specify that the name of the instruction is hello, and the second parameter is the function that returns the instruction object. So in the above code, the function mainly uses two properties to define this hello directive:
1. The restrict[string] attribute is mainly used to specify what form of expressions can be used in HTML code. A represents attributes, E represents elements, C represents classes, and M represents comments. In actual situations, we generally use the two methods of AE.
2. The template[string or function] attribute specifies the HTML markup generated by the command after it is compiled and linked by Angular. This attribute can be as simple as only one HTML text inside, or it can be particularly complex. When the value of the attribute is function, the method returns a string representing the template, and the expression {{}} can also be used in it.
template: function () { return '<button>click me</button>'; }But in general, the template attribute will be replaced by templateUrl, and it is used to point to an external file address, so we usually place the template in an external HTML file, and then use templateUrl to point to it.
When defining instructions, in addition to the above two most basic attributes, we will also use many other attributes. So let’s talk about them one by one:
1. Priority[number] attribute, this attribute is used to specify the priority of custom instructions. When there are more than one instruction on a DOM element, you need to compare the priority of the instructions. Instructions with higher priority are executed first. This priority is used to sort the compile function before executing the instruction. So we will talk about the compile function carefully below.
2. Terminal[boolean] attribute, this parameter is used to define whether to stop instructions on the current element that have lower priority than this instruction. If the value is true, it is normal. It is executed in the order of priority. If it is set to false, instructions on the current element that have lower priority than this instruction will not be executed.
3. Replace[boolean] attribute, this attribute is used to specify whether the generated HTML content will replace the HTML element that defines this directive. When we set the value of this property to true, open the console and look at it, you will find that the element generated by this instruction will look like this:
When we set to false it will look like this:
.
4. link[function] attribute. In the above example, the command we customized actually does not have much meaning. This is just the simplest command. There are many attributes we have not defined for it, so it is not of much use. For example, this link function includes three parameters: scope, element, and attrs. This link function is mainly used to add event monitoring to DOM elements, monitor model attribute changes, and update DOM. It has three parameters:
1: scope parameter. When we do not define scope attributes for the instruction, it represents the scope of the parent controller.
2: The element parameter is the jQLite (a subset of jQuery) of the instruction to wrap the DOM element. If you introduced jQuery before introducing AngularJS, then this element is the jQuery element, not the jQLite element. Since this element has been wrapped by jQuery/jQLite, we no longer need to use $() to wrap it when performing DOM operations.
Three: the attrs parameter, which contains the standardized parameter object of the attributes of the element where the directive is located.
5. The scope[boolean or object] attribute is used to define the scope of the instruction. It is false by default. That is to say, the instruction inherits the scope of the parent controller. You can use the attributes in the scope of the parent controller at will, but in this way, it will pollute the attributes in the parent scope, which is not advisable. So we can let scope take the following two values: true and {}.
When true, it means that Angular creates a scope inherited from the parent scope for the instruction.
var myapp=angular.module('myapp',[]) .controller('myctrl',['$scope', function ($scope) { $scope.color='red'; }]) .directive('hello', function () { return{ restrict:'AECM', replace:true, template:'<button ng-click="sayhello()" style="background-color: {{color}}">click me</button>', scope:true, link: function (scope,elements,attrs) { elements.bind('click', function () { elements.css('background-color','blue'); }) } } } })Here we define a color attribute for the parent scope and assign it to red. In the scope attribute of the hello directive, we give true, so angular creates a scope inherited from the parent scope for this directive. Then in the template attribute, we use {{}} to use the color attribute inherited from the parent scope, so the button will be red.
When {}, it means that an isolated scope is created and the properties of the parent scope will not be inherited. But sometimes we also need to access the properties or methods in the parent scope, so what should we do? angular has long thought of this for us. There are three ways to remember the above operations:
1: Use @ to implement one-way binding. If we only give scope this {} value, then the background color of the button in the above code will be gray. , and if we need to use the color attribute of the parent scope, we can write this:
scope{ color:'@color'} <hello color="{{color}}"></hello>There are two points to note here: 1. The property color in scope represents the color in the expression {{}}, and the two must be consistent. 2. The value of the attribute color in scope, that is, the color after @, represents the attribute color in the HTML element below, so the two must also be consistent. If the attribute name here is the same as the name used in the expression {{}} in the template, the attribute name after @ can be omitted and written in the following form.
scope{ color:'@'}From the value of scope in the instruction, it can be seen that the color in the expression {{}} in the instruction template points to the color attribute of the current element element, and the value of this color attribute is the value of the parent scope's property color. The parent scope passes its color attribute value to the color attribute of the current element, and then the color attribute passes the value to the color in the expression in the template. This process is one-way.
Two: Use = to implement two-way binding
.directive('hello', function () { return{ restrict:'AECM', replace:true, template:'<button style="background-color: {{color}}">click me</button>', scope:{ color:'=' }, link: function (scope,elements,attrs) { elements.bind('click', function () { elements.css('background-color','blue'); scope.$apply(function () { scope.color='pink'; }) }) } } } })<hello color="color"></hello><input type="text" ng-model="color"/>
Here we have two-way binding the color attribute in the scope of the instruction and the color attribute in the parent scope, and add a click event to the instruction's link function. Clicking the button will change the color of the button, and change the value of the color attribute of the instruction scope, and then add an input tag to the HTML page, output or input the value of the color attribute of the parent scope. There is a place to note here: the value of the current element's attribute name does not need to add the expression {{}}, because the parent scope here passes a real scope data model, not a simple string, so we can pass simple strings, arrays, and even complex objects to the scope of the instruction. Now let's see what happens when clicking this button.
Here we can see that the color of the button has changed to pink, which means that the click changes the color attribute of the scope of the command, which causes the color of the button to change. But here is not just the button that has changed. Pay attention to the value in the input form has also become pink, which means that the color attribute of the parent scope has also changed. In addition, let's enter a color into the input to see what changes have occurred.
, it can be seen that when we enter another color in the form, the color of the button also changes, which means that the color attribute of the scope of the command has been changed. In summary, we can find that using '=' is a two-way binding.
Three: Use & call the method in the parent scope
var myapp=angular.module('myapp',[]) .controller('myctrl',['$scope', function ($scope) { $scope.color='red'; $scope.sayhello= function () { alert('hello'); }; }]) .directive('hello', function () { return{ restrict:'AECM', replace:true, template:'<button ng-click="sayhello()" style="background-color: {{color}}">click me</button>', scope:{ color:'=', sayhello:'&' }, link: function (scope,elements,attrs) { elements.bind('click', function () { elements.css('background-color','blue'); scope.$apply(function () { scope.color='pink'; }) }) } } })<hello color="color" sayshello="sayhello()"></hello><input type="text" ng-model="color"/>
Here we also have two things to note: 1. We not only need to use the ng-click directive in the template to bind the method in the parent scope to be called, but also add a property to the current element, and this property points to the method of the parent scope to be called. 2. The three of the instruction scope attribute sayshello, the current element attribute sayshello, and the event method name that binds the template must be consistent. Then we can click the button and a dialog box pops up.
6. Transclude[boolean] attribute, this attribute is used to allow us to specify whether the directive can contain any content
.directive('hello', function () { return{ restrict:'AECM', replace:true, transclude:true, scope:{}, template:'<div ng-transclude></div>', } }) <hello> hello <span>{{color}}</span></hello>When its value is true, this is the value output on the page. When false, the page will be blank. There is a place to pay attention to here, which is <span>{{color}}</span>. The color here is the color in the parent scope. It is not the color attribute of scope in the directive.
7. compile[function] parameter. This method has two parameters element, attrs. The first parameter element refers to the element where the instruction is located, and the second attrs refers to the standardized list of parameters assigned on the element. Here we also have a place to note: the compile function cannot access 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).
.directive('hello', function () { return{ restrict:'AECM', replace:true, translate:true, template:'<button ng-click="sayhello()" style="background-color: {{color}}">click me</button>', scope:{ color:'=', sayhello:'&' }, compile: function (element,attrs) { return function (scope,elements,attrs) { elements.bind('click', function () { elements.css('background-color','blue'); scope.$apply(function () { scope.color='pink'; }) }) }; } } })Now let's click this button
We found that what happened after clicking the button here is the same as the one that used the link attribute before, and there is actually not much difference.
In fact, in most cases, we only need to use the link function. This is because most instructions only need to consider registering event listening, monitoring model, and updating DOM, which can be done in link functions. However, for instructions like ng-repeat, DOM elements need to be cloned and repeated multiple times, and the compile function is done before the link function is executed. So why do we need two separate functions to complete the generation process, and why can't we just use one? To answer this question well, we need to understand how directives are compiled in Angular!
8. How are instructions compiled
When our angular application boot is started, angular will use the $compile service to traverse the DOM element. After all instructions are recognized, the compile method of the instruction will be called, a link function will be returned, and then the link function will be added to the list of link functions executed later. This process is called the compilation stage. Instructions like ng-repeat need to be repeated and cloned many times. The compile function is executed only once during the compilation stage and these templates are copied, but the link function is executed for each copied instance. So we can handle it separately to improve our performance (this sentence is a bit unrealistic, I copied it from other places.
9. Controller[string or function] and require[string or string[]] parameters. When we want to allow other instructions to interact with your instructions, we need to use the controller function. When another directive wants to interact, it needs to declare its reference to the controller instance of your directive.
.directive('hello', function () { return{ scope:{}, require:'^he', compile: function (element,attrs) { return function (scope,elements,attrs,cntIns) { cntIns.fn() }; } } }) .directive('he', function () { return { restrict:'AE', scope:{}, controller: function ($scope, $compile, $http) { this.fn= function () { alert('hello'); }; } } })<he> <hello color="color" sayshello="sayhello()"></hello></he>
When the page is loaded, a dialog box will pop up.
Well, the above is what I learned about the instructions I have learned during this period of time. Let’s write this one.
The above comprehensive analysis of the instructions in AngularJS (must read) is all the content I share with you. I hope you can give you a reference and I hope you can support Wulin.com more.