Preface
In addition to the built-in directives in AngularJS, we can also create custom directives.
Add custom directives via the .directive() function.
When calling a custom directive, you need to add a custom directive name to the HTML element.
Custom directive naming rules: use camel nomenclature to name, that is, the first letter except the first word must be capitalized. For example: myDirective.
When calling this directive on the html page, you need to split it with -, such as: my-directive. Sample code:
<body ng-app="myApp"> <my-directive></my-directive> <script> var app = ("myApp", []); ("myDirective", function() { return { template : "<h1>Template: You can write your own html page code</h1>" }; }); </script> </body>
Four ways to call custom directives on html page
By adding restrict attribute to custom directives, the html page is called according to the settings of different values, such as:
var app = ("myApp", []); ("myDirective", function() { return { restrict : "A",//Can only be called through attributes template : "<h1>Custom command!</h1>" }; });
The difference in restrict value determines the different calling methods
Attribute value | Call method | Example |
---|---|---|
A (Attribute initial letter) | Attribute name | <div my-directive></div> |
C (Class initial letter) | Class Name | <div class='my-directive'></div> |
E (Element initial letter) | Element name | <my-directive></my-directive> |
M | Comments | <!-- Directive: my-directive> |
The default value of restrict is EA, that is, custom instructions can be called through element names and attribute names on the html page.
Detailed explanation of custom directive properties
property | Value Type | illustrate |
---|---|---|
restrict | string | Instructions are called, A, C, E, M |
priority | number | Priority for instruction execution |
template | string | The template used by the directive can write the html page code here. Only choose one of the templateUrl |
templateUrl | string | Load the template from the specified url address. Only choose one of the template |
replace | boolean | Whether to replace the current element with a template. true: Replace the directive tag with the content defined in temple, and there will no longer be a <my-directive> tag on the page; false: then append (append) on the current element, that is, the content of the template is packaged inside the <my-directive> tag. Default false. |
transclude | boolean | Whether to transfer the content of the current element to the template |
scope | boolean /object | Specifies the scope of the directive. false (default): Use the parent scope as its own scope (if each tag that references a custom directive changes the value of a certain variable, it will affect the value of other tags). true: Create a new scope that inherits the parent scope (the variables between two tags that refer to custom directives do not affect each other). JavaScript Object: Isolated from the parent scope and specifies variables that can be accessed from the parent scope |
controller | function | Define interface functions that interact with other instructions |
require | string | Specify other instructions to depend on |
link | function | Operate DOM programmatically, including adding listeners, etc. |
compile | function | Programmatically modify the copy of the DOM template and return the link function |
Extend knowledge in the table
If the html page code spelled in template is very complicated and it will be too troublesome to spell strings, here we can choose templateUrl. We can separate the html page code to spell it into a page, such as; then specify the path to the html file, such as templateUrl:”. When using this custom instruction, an http request will be automatically sent to obtain the corresponding template content. The disadvantage of this is that there is an additional http request. Don't worry, you can improve:
angularjs specifies that templates can also be defined with <Script> tags:
<script type="text/ng-template" id=""> <div>For custom directive templatesScriptHow to define tags,Must be placedhtmlpageng-controllerInside the tag where the instruction is located</div> </script>
The above code is written in the tag of the ng-controller directive of the html page, so you don't have to request it anymore. Example:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="/libs//1.4.6/"></script> </head> <body > <div ng-app="myApp" ng-controller="myController"> <!-- Reference custom directives --> <my-directive></my-directive> <!-- Template code:Must be placedmyControllerInside the tag --> <script type="text/ng-template" id=""> <div> Custom directive templatestemplateUrlform</div> </script> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope) { }); //Create custom command ("myDirective", function() { return { restrict:'E', templateUrl : "" }; }); </script> </body> </html>
When there are multiple templates, we can concentrate all the templates in one file, just load them once, and call different templates according to the id.
Defines whether to transfer the contents of the current element (custom directive for the html page) to the template.
The tags in the template that want to receive the content of the current element need to use the ng-transclude directive.
<body > <div ng-app="myApp" ng-controller="myController"> <!-- Reference custom directives --> <my-directive>Customize the content of the specified command</my-directive> <!-- Template code --> <script type="text/ng-template" id=""> <div> Template content</div> <div ng-transclude></div>//The template receives the content between the above custom instructions </script> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope) { }); //Create custom command ("myDirective", function() { return { templateUrl : "", transclude : true//Transfer to template }; }); </script> </body>
3. What is the parent scope of scope
The range that the controller can control for the html page that references custom directives. The parent scope of the following code is the scope controlled by myController
<body > <div ng-app="myApp" ng-controller="myController"> <my-directive></my-directive><!-- Reference custom directives --> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope){ }); //Create custom command ("myDirective", function() { return { template : "<h1>Custom command!</h1>" }; }); </script> </body>
The usage of the value of the property is an object
The usage of AngularJS built-in directive: ng-model=”obj”. The two-way binding value of the variable obj is changed in the controller, and the html page also changes. This shows that built-in instructions can not only be used as attributes, but also dynamically change values. If you don’t understand this, look at the basic syntax. The following code:
<div ng-app="myApp" ng-controller="myController"> Content to change dynamically: <input ng-model="obj"> </div> <script> var app = ('myApp', []); ('myController', function($scope) { $ = "This string value will be synchronized to html"; }); </script>
Of course, custom instructions also need to implement this function. When the scope attribute is an object, you can specify an attribute that can bind the value to the custom directive. It is also necessary to explain here that this scope property is the same as the scope parameter in the link property in the custom directive.
<!-- =Usage of symbols--> <body > <div ng-app="myApp" ng-controller="myController"> <!-- Reference custom directives:objVariables and controllersobjcThe variable has two-way bound value --> <my-directive speak="obj"></my-directive> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope) { $="Parent scope";//The value assigned to the custom instruction attribute by the parent scope }); //Create custom command ("myDirective", function() { return { template : "<p>Template Content</p>", scope:{ title:"=speak"//Define a speak attribute for custom instructions on the html page. If written in the format of title:"=", the attribute name in the custom directive is title. }, link: function postLink(scope, iElement, iAttrs) { ()//The value printed here is the same as the value in the controller } }; }); </script> </body>
With the previous example, let’s talk about the binding strategy: that is, use symbol prefixes to pass values to custom instructions. It is a key-value pair, the key is used in a custom instruction, and the string after the symbol in the value is the attribute name of the html page custom instruction; if there are only symbols in the value, the attribute name of the html page custom instruction is the key name.
symbol | illustrate | Example |
---|---|---|
@ | Value pass, one-way binding. The value of the val property in the html page custom directive can be passed to the scope of the link. The first way to write - str: "@", this way to write the command attribute of the html page is called str | str: "@val", attribute name is val |
= | Bidirectionally bind data to the attributes of the instruction, and the data value can be of any type. The first way to write: name: "=", this way to write the custom instruction attribute name of the html page is name | name: "=username", the attribute name is username |
& | Use a function in the parent scope that can be called in the directive. The first way to write: getName: "&", this way to write the custom instruction attribute name of the html page is gegName | getName: "&getUserName", the attribute name is getUserName |
The other two symbol usages:
<!-- @Usage of symbols --> <body > <div ng-app="myApp" ng-controller="myController"> <!-- Reference custom directives --> <my-directive title="obj" str="abcd">Customize the content of the specified command555</my-directive> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope) { $="Parent scope";//The value assigned to the custom instruction attribute by the parent scope }); //Create custom command ("myDirective", function() { return { template : "<p >Template Content</p>", scope:{ title:"=", str:"@" }, link: function postLink(scope, iElement, iAttrs) { () () } }; }); </script> </body>
<!-- &Usage of symbols --> <body > <div ng-app="myApp" ng-controller="myController"> <!-- Reference custom directives --> <my-directive fun="test()"></my-directive> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope) { $ = function(){ ('The custom directive will call the method, so this sentence will be printed to the console') } }); //Create custom command ("myDirective", function() { return { template : "<p >Template Content</p>", scope:{ fun:"&"//The attribute name is directly fun }, link: function postLink(scope, iElement, iAttrs) { ();//Calling the parent scope method, it seems that it cannot pass parameters, so I haven't studied it in depth. } }; }); </script> </body>
property
The controller attribute is used to provide an external interface, that is, the custom instruction will be called by other custom instructions. The so-called interface is the variable or method after this.
The parameters that controller can use, scope, node, node attributes, and node content migration, can all be passed in through dependency injection, so you can only write the parameters you want to use according to your needs, including $scope, Z$element, $attrs, $transclude.
The instructions that call the custom instruction need to be placed between the instructions. Assume that the firstDirective directive is a custom directive to be called, and the expander is the caller directive. as follows:
<first-directive> <expander ng-repeat="item in list" attribute="list">{{}}:{{}}</expander> </first-directive>
Since there are instructions inside firstDirective, firstDirective must configure the transclude property to true. The code is as follows:
// Custom directives for being called ('firstDirective',function(){ return { template : '<div ng-transclude></div>', replace : true, transclude : true, controller :function(){ = function(val){ var data = 3 * val; return data; } = "abc"; } } });
Custom directives that call other directives must be configured with the require attribute to specify the instruction name. Then, the instructions to be called can be injected into the link function.
//Custom command ('expander',function(){ return { templateUrl : '', replace : true, transclude : true, require : '^?firstDirective',//Reference other custom directives, ^ means starting from the parent node, ? means telling $compile service. If the required directive is not found, do not throw an exception scope : { title : '=attribute' }, link : function(scope,element,attris,firstDirct){//injection ()//Call variables of other instructions ((6)) //Calling other instructions methods } }; });
Attribute usage
The method after link is responsible for executing DOM operations and registering event listeners in instructions. The link function has five parameters (scope, element, attrs, controller, linker). Parameter explanation of link method:
scope: It is the same as the scope property in the custom directive. It is a reference to the directive scope, so it can be changed to other names such as sco. The scope variable is not defined at initialization, and the link method registers the monitor's monitoring value change event.
element: References to the DOM element containing directives, the link method generally operates the instance through jQuery (if jquery is not loaded, you can also use Angular's jqLite).
controller: Used in case of nested instructions. This parameter is used to provide references to the child instruction to the parent instruction, allowing interaction between the instructions, as in the previous example.
Note: When the link method is called, the scope variables passed by the value ("@") will not be initialized, they will be initialized at another point in the life of the instruction. If you need to listen to this event, you can use the scope.$watch method.
The difference from compile
The compile function has three parameters (cElement, cAttrs, cLinker). Using the compile function, you can change the original dom (template element) before ng creates the original dom instance and creates the scope instance; it can be applied to situations where multiple element instances need to be generated but only one template element, ng-repeat is a best example. It changes the original dom in the compile function stage to generate multiple original dom nodes, and then each generates an element instance. Because compile will only run once, it can improve performance when you need to generate multiple element instances.
The link function has five parameters (scope, element, attrs, ctrl, linker).
Link is divided into pre-link and post-link. It is directly represented by pre and post in the code. When we use link directly, the default is the same as post. I found an example online to illustrate the difference, the code is as follows:
<body> <div ng-app="myApp" ng-controller="myController"> <level-one> <level-two> <level-three> Hello </level-three> </level-two> </level-one> </div> <script> //Create module var app = ('myApp', []); //Create a controller ('myController', function($scope) { }); //Custom command function createDirective(name){ return function(){ return { restrict: 'E', compile: function(tElem, tAttrs){ (name + ': compile => ' + ()); return { pre: function(scope, iElem, iAttrs){ (name + ': pre link => ' + ()); }, post: function(scope, iElem, iAttrs){ (name + ': post link => ' + ()); } } } } } } ('levelOne', createDirective('levelOne')); ('levelTwo', createDirective('levelTwo')); ('levelThree', createDirective('levelThree')); </script> </body>
Note the print result:
levelOne: compile => <level-two> <level-three> Hello </level-three> </level-two> levelTwo: compile => <level-three> Hello </level-three> levelThree: compile => Hello levelOne: pre link => <level-two> <level-three> Hello </level-three> </level-two> levelTwo: pre link => <level-three> Hello </level-three> levelThree: pre link => Hello levelThree: post link => Hello levelTwo: post link => <level-three> Hello </level-three> levelOne: post link => <level-two> <level-three> Hello </level-three> </level-two>
Analysis of print results:
Run the compile function in the levellone instruction, and ng will recursively traverse its dom node, and then repeat these operations on level-two and level-three. So three consecutive compiles will be printed in turn.
pre will be executed after all compiles are executed and before all posts. This allows you to execute some other code before executing the post, some similar to AOP.
From the above results, we can see that the execution order of post is level three and finally level one, that is, the associated post-link function is called in reverse. The advantage of doing this is that when we run levellone, we ensure that leveltwo and levelthree have been executed, which will be safer. So the default link is post.
An example of pagination I've made
The reason for displaying this code is to show some friends the real project. The extra items have been deleted, so I won’t talk about the specific injection here.
html page code:
<div class="wp-20" ng-controller="AppStatisticController" ng-cloak> <div class="panel-footer"> <s-pagination conf="paginationConf"></s-pagination> </div> </div>
Controller code:
"use strict";//strict define(["application-configuration", "s-pagination", "tableDataService"], function (app) { ("AppStatisticController", ["$scope", "$rootScope", "$stateParams","$http", "tableDataService", function($scope, $rootScope, $stateParams, $http, tableDataService) { var getTableDataSuccess = function(result) { if( == 1) { $ = ; $ = ; $ = ; $ = ; }else if( == 2){ //The box pops up, no data was found } else { alert(); } }; var getTableDataError = function(result) { alert(result); }; /* Important code, this paginationConf is two-way bound to data with custom instructions*/ $ = { currentPage: 1, itemsPerPage: 10, pagesLength: 9, search: false, onChange: function() { var param = { "pageNo": , "pageSize": , "timeType": $, "adStyle":$, }; = $; ( param, "ims/", getTableDataSuccess, getTableDataError ); } }; $scope.$watch("formData",function(newValue,oldValue, scope) { if( == ) { $ = true; } }, true); }]); });
Custom directive code: It is also considered a paging plugin for angularJS
/** * Paging plugin encapsulation * @date 2016-05-06 * @author Peter */ ('', []).directive('sPagination',[function(){//Custom command return { restrict: 'E',//Only for element name calls template: '<div class="page-list">' + '<ul class="pagination" ng-show=" > 0">' + '<li ng-class="{disabled: == 1}" ng-click="prevPage()"><span>&laquo;</span></li>' + '<li ng-repeat="item in pageList track by $index" ng-class="{active: item == , separate: item == \'...\'}" ' + 'ng-click="changeCurrentPage(item)">' + '<span>{{ item }}</span>' + '</li>' + '<li ng-class="{disabled: == }" ng-click="nextPage()"><span>&raquo;</span></li>' + '</ul>' + '<div class="page-total" ng-show=" > 0">' + 'The<input type="text" ng-model="jumpPageNum" ng-keyup="jumpToPage($event)"/>Page ' + '每Page<select ng-model="" ng-options="option for option in "></select>' + '/common<strong>{{ }}</strong>strip' + '</div>' + '<div class="no-items" ng-show=" <= 0">No data yet</div>' + '</div>', replace: true, scope: { conf: '='//Bidirectional binding data }, link: function(scope, element, attrs){ // Change the current page = function(item) { if(item == '...'){ return; }else{ = item; } }; // Define the length of the page must be odd (default:5) = parseInt() ? parseInt() : 5 ; if( % 2 === 0){ // If it is not an odd number, it will be handled = -1; } // if(!){ = [10, 20, 30, 40, 50]; } // pageList array function getPagination(newValue, oldValue) { //Added attribute search is used to trigger when additional search conditions are changed if(newValue[1] != oldValue[1] || newValue[2] != oldValue[2]) { = true; } // = parseInt() ? parseInt() : 1; // = parseInt() ? parseInt() : 0; // (default:15) = parseInt() ? parseInt() : 15; // numberOfPages = (/); // judge currentPage > if( < 1){ = 1; } // If the total number of paging > 0, and the current page is greater than the total number of paging if( > 0 && > ){ = ; } // jumpPageNum = ; // If itemsPerPage is not in the perPageOptions array, add itemsPerPage to this array var perPageOptionsLength = ; // Define the status var perPageOptionsStatus; for(var i = 0; i < perPageOptionsLength; i++){ if([i] == ){ perPageOptionsStatus = true; } } // If itemsPerPage is not in the perPageOptions array, add itemsPerPage to this array if(!perPageOptionsStatus){ (); } // sort the options (function(a, b){return a-b}); = []; if( <= ){ // If the total number of pages is less than or equal to the length of the page, it will be displayed directly if it is less than or equal to the page. for(i =1; i <= ; i++){ (i); } }else{ // The total number of pages is greater than the page length (this is divided into three situations: 1. There is no left...2. There is no right...3. There is no left...) // Calculate the center offset var offset = ( - 1)/2; if( <= offset){ // There is no left... for(i =1; i <= offset +1; i++){ (i); } ('...'); (); }else if( > - offset){ (1); ('...'); for(i = offset + 1; i >= 1; i--){ ( - i); } (); }else{ // In the last case, there are... (1); ('...'); for(i = (offset/2) ; i >= 1; i--){ ( - i); } (); for(i = 1; i <= offset/2; i++){ ( + i); } ('...'); (); } } if(){ //Request data if() { (); = false; } } scope.$ = ; } // prevPage = function(){ if( > 1){ -= 1; } }; // nextPage = function(){ if( < ){ += 1; } }; // Jump to page = function(){ = (/[^0-9]/g,''); if( !== ''){ = ; } }; scope.$watch(function() { if(!) { = 0; } if(()) { = false; } var newValue = [, , , ]; return newValue; }, getPagination, true); } }; }]);
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.