For instructions, they can be simply understood as functions that run on specific DOM elements, and instructions can extend the functions of this element.
First, let’s take a look at a complete parameter example and then introduce the functions and usages of each parameter in detail:
angular.module('myApp', []) .directive('myDirective', function() { return { restrict: String, priority: Number, terminal: Boolean, template: String or Template Function: function(tElement, tAttrs) {...}, templateUrl: String, replace: Boolean or String, scope: Boolean or Object, transclude: Boolean, controller: String or function(scope, element, attrs, transclude, otherInjectables) { ... }, controllerAs: String, require: String, link: function(scope, iElement, iAttrs) { ... }, compile: // Return an object or connection function, as shown below: function(tElement, tAttrs, transclude) { return { pre: function(scope, iElement, iAttrs, controller) { ... }, post: function(scope, iElement, iAttrs, controller) { ... } } return function postLink(...) { ... } } }; });restrict[string]
restrict is an optional parameter. Used to specify in the form of the instruction being declared in the DOM. The default value is A, that is, it is declared in the form of an attribute.
The optional values are as follows:
E (element)
<my-directive></my-directive>
A (property, default value)
<div my-directive="expression"></div>
C (Class name)
<div></div>
M (Note)
<--directive:my-directive expression-->
Generally, considering the compatibility of the browser, it is strongly recommended that the default attributes be declared immediately in the form of attributes. The last method is recommended not to use the qualifying index when it is not required.
Code:
angular.module('app',[]) .directive('myDirective', function () { return { restrict: 'E', template: '<a href="http://www.baidu.com">Baidu</a>' }; })HtmlCode: <my-directive></my-directive>Effect:
priority[int]
Most instructions ignore this parameter and use the default value 0, but some scenarios are very important or even necessary to set high priority. For example, ngRepeat sets this parameter to 1000, so that it can ensure that on the same element it is always called before other instructions.
terminal[bool]
This parameter is used to stop running instructions on the current element that have lower priority than this instruction. However, instructions with the same priority as the current instruction will still be executed.
For example: ngIf has a priority slightly higher than ngView (they are actually terminal parameters). If the expression value of ngIf is true, ngView can be executed normally, but if the value of ngIf expression is false, ngView will not be executed because the priority of ngView is low.
template[string or function]
The template parameter is optional and must be set to one of the following two forms:
A piece of HTML text;
A function that can accept two parameters, the parameters are tElement and tAttrs, and returns a string representing the template. t in tElement and tAttrs stands for template, relative to instance.
First, let’s demonstrate the second usage:
angular.module('app',[]) .directive('myDirective', function () { return { restrict: 'EAC', template: function (elem, attr) { return "<a href='" + attr.value + "'>" + attr.text + "</a>"; } }; })HtmlCode: (The effect is the same as above, no demonstration will be made)
<my-directive value="http://www.baidu.com" text="Baidu"></my-directive> <div my-directive value="http://www.baidu.com" text="Baidu"></div>
templateUrl[string or function]
templateUrl is an optional parameter, which can be of the following type:
A string representing the path of an external HTML file;
A function that can accept two parameters, the parameters are tElement and tAttrs, and returns a string with the path of the external HTML file.
Either way, the URL of the template will be passed through ng's built-in security layer, especially $getTrustedResourceUrl, which protects the template from being loaded by untrusted sources. By default, when calling the directive, the HTML template file will be requested through Ajax in the background. Loading large numbers of templates will severely slow down a client application. To avoid latency, HTML templates can be cached before deploying the application.
Code:
angular.module('app',[]) .directive('myDirective', function () { return { restrict: 'AEC', templateUrl: function (elem, attr) { return attr.value + ".html"; //Of course here we can directly specify the path, and we can include expressions in the template} }; })replace[bool]
replace is an optional parameter. If this parameter is set, the value must be true because the default value is false. The default value means that the template will be inserted into the element that calls this directive as a child element.
For example, under the default value of the above example, the generated html code is as follows:
<my-directive value="http://www.baidu.com" text="Baidu"><a href="http://www.baidu.com">Baidu</a></my-directive>
If replace=true is set
<a href="http://www.baidu.com" value="http://www.baidu.com" text="Baidu">Baidu</a>
According to my observation, this effect will only show actual effect when restrict="E".
After introducing the basic instruction parameters, more important scope parameters are involved...
scope parameter[bool or object]
The scope parameter is optional and can be set to true or an object. The default value is false.
If multiple directives on an element use isolation scope, only one of them can take effect. Only the root element in the directive template can obtain a new scope. Therefore, scope is set to true by default for these objects. The function of the built-in directive ng-controller is to inherit from the parent scope and create a new child scope. It creates a new child scope inherited from the parent scope. The inheritance here will not be described in detail, and it is basically the same as the inheritance in object-oriented.
First, let's analyze a piece of code:
<div ng-app="app" ng-init="name= 'grandfather'"> <div ng-init="name='father'"> First generation: {{ name }} <div ng-init="name= 'son'" ng-controller="SomeController"> Second generation: {{ name }} <div ng-init="name='grandson'"> Third generation: {{ name }} </div> </div> </div> </div> </div> </div>We found that the first generation, we initialize the name as the father, but the second generation and the third generation are actually the same scope, so their name is actually an object, so the effect of this is as follows:
First generation: Father
Second generation: grandson
Third generation: grandson
We are modifying the code to isolate the third generation and then check the effect:
<div ng-app="app"ng-init="name= 'grandfather'"> <div ng-init="name='father'"> First generation: {{ name }} <div ng-init="name= 'son'" ng-controller="SomeController"> Second generation: {{ name }} <div ng-init="name='grandson'" ng-controller="SecondController"> Third generation: {{ name }} </div> </div> </div> </div> </div> </div> angular.module('app', []) .controller('SomeController',function($scope) { }) .controller('SecondController', function ($scope) { })The effects are as follows:
First generation: Father
Second generation: Son
Third generation: grandson
After modifying the code, let’s take a look at the inheritance:
<div ng-app="app"ng-init="name= 'Grandfather'"> <div> First generation: {{ name }} <div ng-controller="SomeController"> Second generation: {{ name }} <div ng-controller="SecondController"> Third generation: {{ name }} </div> </div> </div> </div> </div> </div>The effects are as follows:
The first generation: Grandfather's kiss
The second generation: Grandfather's kiss
The third generation: Grandfather's kiss
If you want to create a directive that can inherit scope from an external prototype and set the scope property to true, it is simply an inheritable isolation, that is, it cannot reversely affect the parent scope.
Let’s take a look at another example:
angular.module('myApp', []) .controller('MainController', function ($scope) { }) .directive('myDirective', function () { return { restrict: 'A', scope:false,//Switch to {}, true test priority: 100, template: '<div>Internal:{{ myProperty }}<input ng-model="myProperty"/></div>' }; });Html code:
<div ng-controller='MainController' ng-init="myProperty='Hello World!'"> External: {{ myProperty}} <input ng-model="myProperty" /> <div my-directive></div> </div>When we change the scope value we will find
false: inherit but not isolate
true: Inherit and isolate
{}: Isolated and not inherited
transclude
transclude is an optional parameter. The default value is false. Embedding is often used to create reusable components, a typical example is a modal dialog box or a navigation bar. We can pass all the entire template, including the instructions in it, into one instruction by embedding it. The inside of the directive can access the scope of the external directive, and the template can also access the external scope objects. In order to pass scope in, the value of the scope parameter must be set to isolate the scope by {} or true. If the scope parameter is not set, the scope inside the directive will be set to the scope of the incoming template.
Use transclude: true only if you want to create a directive that can contain any content.
Let's look at two examples - navigation bar:
<div side-box> <div> <a href="">Graphics</a> <a href="">ng</a> <a href="">D3</a> <a href="">Front-end</a> <a href="">Startup</a> </div> </div>
JsCode:
angular.module('myApp', []) .directive('sideBox', function() { return { restrict: 'EA', scope: { title: '@' }, translate: true, template: '<div><div><h2>' + '{{ title }}</h2><span ng-transclude></span></div></div>' }; });This code tells the ng compiler to put what it gets from the DOM element where it discovers the ng-transclude directive.
Let’s look at an example from the official website:
angular.module('docsIsoFnBindExample', []) .controller('Controller', ['$scope', '$timeout', function($scope, $timeout) { $scope.name = 'Tobias'; $scope.hideDialog = function () { $scope.dialogIsHidden = true; $timeout(function () { $scope.dialogIsHidden = false; }, 2000); }; }]) .directive('myDialog', function() { return { restrict: 'E', transclude: true, scope: { 'close': '&onClose' }, templateUrl: 'my-dialog-close.html' }; });my-dialog-close.html
my-dialog-close.html<div> <a href ng-click="close()">×</a> <div ng-transclude></div></div>
index.html
<div ng-controller="Controller"> <my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()"> Check out the contents, {{name}}! </my-dialog></div>If the instruction uses the transclude parameter, the controller cannot monitor changes in the data model normally. It is recommended to use the $watch service in the link function.
controller[string or function]
The controller parameter can be a string or a function. When set to a string, the constructor of the controller registered in the application will be found with the value of the string as the name.
angular.module('myApp', []) .directive('myDirective', function() { restrict: 'A', controller: 'SomeController' })An inline controller can be defined through an anonymous constructor inside the instruction.
angular.module('myApp',[]) .directive('myDirective', function() { restrict: 'A', controller: function($scope, $element, $attrs, $transclude) { // The controller logic is placed here} });We can inject any ng service that can be injected into the controller and we can use it in the instructions. There are also some special services in the controller that can be injected into the instructions. These services include:
1. $scope
The current scope associated with the directive element.
2. $element
The element corresponding to the current instruction.
3. $attrs
An object composed of attributes of the current element.
<div id="aDiv"class="box"></div> has the following attribute object: { id: "aDiv", class: "box" }4. $transclude
The embed link function will be prebined with the corresponding embedding scope. The transclude link function is a function that is actually executed to clone elements and operate the DOM.
angular.module('myApp',[]) .directive('myLink', function () { return { restrict: 'EA', transclude: true, controller: function ($scope, $element,$attrs,$transclude) { $transclude(function (clone) { var a = angular.element('<a>'); a.attr('href', $attrs.value); a.text(clone.text()); $element.append(a); }); } }; });; });;html
<my-link value="http://www.baidu.com">Baidu</my-link>
<div my-link value="http://www.google.com">Google</div>
It is recommended to use transcludeFn only in compile parameters. The link function can isolate instructions from each other, while the controller defines reusable behavior. If we want to expose the API of the current instruction to other instructions, we can use the controller parameter, otherwise we can use link to construct the functionality of the current instruction element (i.e., internal functions). If we use scope.$watch() or want to interact with DOM elements in real time, using links will be a better choice. With embedding, the scope reflected by the scope in the controller may be different from what we expected. In this case, the $scope object cannot be guaranteed to be updated normally. When you want to interact with the scope on the current screen, you can use the scope parameter passed into the link function.
controllerAs[string]
The controllerAs parameter is used to set the alias of the controller so that the controller can be referenced in the view without even injecting $scope.
<div ng-controller="MainController as main"> <input type="text" ng-model="main.name" /> <span>{{ main.name }}</span> </div>JsCode:
angular.module('myApp',[]) .controller('MainController', function () { this.name = "Halower"; });The alias of the controller enables routing and instructions to create anonymous controllers. This ability can create dynamic objects into controllers, and the object is isolated and easy to test.
require[string or string[]]
require is a string representing the name of another instruction. require will inject the controller into the instruction it specifies and serve as the fourth parameter of the link function of the current instruction. The value of a string or array element is the instruction name that will be used in the scope of the current instruction. In any case, the ng compiler will refer to the template of the current instruction when looking for a subcontroller.
compile【object or function】
The compile option itself is not used frequently, but the link function is used frequently. Essentially, when we set the link option, we actually create a postLink() link function so that the compile() function can define the link function. Normally, if the compile function is set, it means that we want to perform DOM operations before the instructions and real-time data are put into the DOM. It is safe to perform DOM operations such as adding and deleting nodes in this function.
The compile and link options are mutually exclusive. If these two options are set at the same time, the function returned by compile will be regarded as a link function, and the link option itself will be ignored.
The compiled function is responsible for converting the template DOM. The link function is responsible for linking the scope and the DOM. The DOM can be manually operated before the scope is linked to the DOM. In practice, this kind of operation is very rare when writing custom instructions, but there are several built-in instructions that provide such functionality.
link
compile: function(tEle, tAttrs, translateFn) { //todo: return function(scope, ele, attrs) { // link function};The link function is optional. If a compiled function is defined, it returns the linked function, so when both functions are defined, the compiled function overloads the linked function. If our instructions are simple and do not require additional settings, we can return a function from the factory function (callback function) to replace the object. If this is done, this function is the link function.
ngModel
It provides a more underlying API to process data in the controller. This API is used to handle data binding, verification, CSS update and other things that do not actually operate the DOM. The ngModel controller will be injected into the instructions along with the ngModel, which contains some methods. In order to access the ngModelController, you must use the require settings.
Common elements used by ngModelController are as follows:
1. In order to set the view value in the scope, the ngModel.$setViewValue() function needs to be called.
The $setViewValue() method is suitable for listening for custom events in custom directives (such as using a jQuery plugin with callback functions), and we would like to set $viewValue and execute digest loops when the callback is called.
angular.module('myApp') .directive('myDirective', function() { return { require: '?ngModel', link: function(scope, ele, attrs, ngModel) { if (!ngModel) return; $(function() { ele.datepicker({ //Callback function onSelect: function(date) { // Set view and call apply scope.$apply(function() { ngModel.$setViewValue(date); }); } }); } }); } }; }); } }; }); } }; }); }; }); }; }); }; }); }; }); }; }); }; }); }; }); }; }); }; });2. The $render method can define the specific rendering method of the view
3. Properties
1. $viewValue
The $viewValue property holds the actual string required to update the view.
2. $modelValue
$modelValue is held by the data model. $modelValue and $viewValue may be different depending on whether the $parser pipeline operates on it.
3. $parsers
The value of $parsers is an array of functions, where the functions are called one by one in the form of pipelines. ngModel The value read from the DOM is passed into the function in $parsers and is processed by the parser in sequence.
4. $formatters
The value of $formatters is an array of functions that are called one by one in the form of a pipeline when the value of the data model changes. It has no effect on the $parser pipeline and is used to format and convert values to display in controls with this value bound.
5. $viewChangeListeners
The value of $viewChangeListeners is an array of functions that are called one by one in the form of a pipeline when the value in the view changes. With $viewChangeListeners, similar behavior can be achieved without using $watch. Since the return value is ignored, these functions do not need to return values.
6. $error
The $error object holds the validator name that has not passed the verification and the corresponding error information.
7. $pristine
The value of $pristine is Boolean, which can tell us whether the user has modified the control.
8. $dirty
The value of $dirty is the opposite of $pristine, which can tell us whether the user has interacted with the control.
9. $valid
The $valid value tells us whether there are errors in the current control. The value is false when there is an error, and the value is true when there is no error.
10. $invalid
The $invalid value tells us whether there is at least one error in the current control, and its value is the opposite of $valid.
The above is the compilation of the instructions and knowledge materials about AngularJS. We will continue to add them later. Thank you for your support for this site!