SoFunction
Updated on 2025-04-04

Detailed explanation of AngularJS custom control instance

This article describes AngularJS custom controls. Share it for your reference, as follows:

Custom command introduction

The AngularJS directive is used to operate Html rendering in AngulaJS applications. For example, interpolated instructions ( {{ }} ), ng-repeat instructions, and ng-if instructions.

Of course you can achieve your own. This is what AngularJS calls "Church HTML Play New Position". This article will tell you how to do it.

Directive Type

The custom command types are as follows:

element
property
CSS class
Comment directives

Here, AngularJS strongly recommends that you use element and attribute types instead of CSS class and comment directives (unless you have to).

The instruction type determines when the instruction is activated. When AngularJS finds an HTML element in the HTML template, the element directive is activated. When AngularJS finds an HTML element attribute, the attribute directive is activated. When AngularJS finds a CSS class, the CSS class directive is activated, and finally, when AngularJS finds an HTML comment, the comment directive is activated.

Basic examples

You can register a directive with the module, like this:

<!-- lang: js -->
myapp = ("myapp", []);
('div', function() {
  var directive = {};
   = 'E'; /* restrict this directive to elements */
   = "My first directive: {{textToInsert}}";
  return directive;
});

Let’s look at the directive() function called in the module. When you call the function, it means you want to register a new instruction. The first parameter of the directive() function is the name of the newly registered directive. This is the name you use when you call it in the HTML template later. In the example, I used 'div', which means that when the HTML template finds that the HTML element type is div, this directive will be activated.

The second parameter passed to the directive function is a factory function. Calling this function returns the definition of a directive. AngularJS calls this function to get a JavaScript object containing the instruction definition. If you have a closer look at the example above, you will know that it returns indeed a Javascript object.

This Javascript object returned from the factory function has two properties: restrict and template fields.

The restrict field is used to set when the directive is activated, whether it is matched to an HTML element, or when it is matched to an element attribute. That is, the instruction type. When restrict is set to E, only HTML elements named div will activate the directive. When restrict is set to A, only the HTML element attribute named div will activate the directive. You can also use AE, which will enable the command to be activated when matching the element name and element attribute name.

The template field is an HTML template that replaces matching div elements. It will treat the matching div as a placeholder and replace it with the HTML template in the same place. That is, the HTML template replaces the matching to HTML elements.

For example, your HTML page has a paragraph of HTML:

<!-- lang: js -->
<div ng-controller="MyController" >
  <div>This div will be replaced</div>
</div>

When AngularJS finds an embedded div, custom directives will be activated. Then replace the div element, and the replaced HTML will become like this:

<!-- lang: js -->
My first directive: {{textToInsert}}

Then you see that this HTML contains an interpolation instruction ({{textToInsert}}). AngularJS will be executed again to display the actual value of the interpolated instruction. The $ property will then replace the interpolated instruction placeholder on this HTML point.

template and templateUrl properties

The easiest example of creating custom directives is the above. Your directive is used to generate HTML, and you put HTML into the template property of the directive definition object. The following example is a repetition of the simplest example above, note the template part:

<!-- lang: js -->
myapp = ("myapp", []);
('div', function() {
  var directive = {};
   = 'E'; /* restrict this directive to elements */
   = "My first directive: {{textToInsert}}";
  return directive;
});

If the HTML template gets bigger, writing it in a Javascript string will definitely be very difficult to maintain. You can put it in a separate file, and AngularJS can load it in through this file. Then put the URL of the HTML template file into the templateUrl property of the directive definition object. Here is an example:

<!-- lang: js -->
myapp = ("myapp", []);
('div', function() {
  var directive = {};
   = 'E'; /* restrict this directive to elements */
   = "/myapp/html-templates/";
  return directive;
});

AngularJS then loads the HTML template from the URL set in the templateUrl property.

Use a separate HTML template file to set the templateUrl property, which will be more useful when you want to create more general instructions, such as instructions to display user information. example:

<!-- lang: js -->
myapp = ("myapp", []);
('userinfo', function() {
  var directive = {};
   = 'E'; /* restrict this directive to elements */
   = "/myapp/html-templates/";
  return directive;
});

The example creates a directive that will be activated when AngularJS finds an <userinfo> element. AngularJS loads the template pointing to /myapp/html-templates/ and parses it, just as if it was embedded in the previous HTML file from the beginning.

Isolate $scope from directive

In the example above, the userinfo directive is hard bound to $scope because the HTML template directly references the textToInsert property. Direct reference to $scope makes it difficult to reuse when direct reference to the command in the same controller because the value of $scope in the same controller is the same. For example, when you write this in the HTML of the page:

<!-- lang: js -->
<userinfo></userinfo>
<userinfo></userinfo>

These two <userinfo> elements are replaced by the same HTML template and then bound to the same $scope variable. The result is that the two <userinfo> elements will be replaced by the same HTML code.

In order to bind two <userinfo> elements to different values ​​in $scope, you need to give the HTML template an isolate scope.

The so-called isolate scope is an independent scope object bound to the directive. Here is an example of the definition:

<!-- lang: js -->
('userinfo', function() {
  var directive = {};
   = 'E';
   = "User : {{}} {{}}";
   = {
    user : "=user"
  }
  return directive;
})

Please see the two interpolated directives {{}} and {{}} in the HTML template. Note the user. section. and properties. It is a Javascript object with user attribute. So it becomes an isolate scope object, and now the HTML template is tied to (through {{}} and {{}} interpolation instructions).

Set to "=user". It means that , which is bound to the attribute in scope (not isolate scope), the attribute in scope is passed into the <userinfo> element through the user attribute. It sounds quite difficult, just look at the example:

<!-- lang: js -->
<userinfo user="jakob"></userinfo>
<userinfo user="john"></userinfo>

Both <userinfo> elements have user attributes. The value of user points to the property with the same name in $scope. The attributes in the specified $scope will be used in the isolate scope object of userinfo.

Here is a complete example:

<!-- lang: js -->
<userinfo user="jakob"></userinfo>
<userinfo user="john"></userinfo>
<script>
('userinfo', function() {
  var directive = {};
   = 'E';
   = "User : <b>{{}}</b> <b>{{}}</b>";
   = {
    user : "=user"
  }
  return directive;
});
("MyController", function($scope, $http) {
  $ = {};
  $ = "Jakob";
  $ = "Jenkov";
  $ = {};
  $ = "John";
  $ = "Doe";
});
</script>

compile() and link() functions

If you need to do more advanced operations in your directives, and you can't just use HTML templates, you can consider using compile() and link() functions.

The compile() and link() functions define how the directives modify the matching HTML.

When the instruction is first compiled by AngularJS (the first time it was discovered in HTML), the compile() function is called. The compile() function will configure this element in one-time.

Then compile() function returns link() as the end. The link() function will be called every time the element is bound to $scope data.

Here is an example:

<!-- lang: js -->
<script>
myapp = ("myapp", []);
('userinfo', function() {
  var directive = {};
   = 'E'; /* restrict this directive to elements */
   = function(element, attributes) {
    // do one-time configuration of element.
    var linkFunction = function($scope, element, atttributes) {
      // bind element to data in $scope
    }
    return linkFunction;
  }
  return directive;
});
</script>

The compile() function takes two parameters: element and attributes.

The element parameter is a DOM element wrapped by jqLite. AngularJS has a simplified version of jQuery that can be used to manipulate DOM, so the DOM operation of element is the same as you know in jQuery.

The attributes parameter is a Javascript object that contains all the attribute collections in the DOM element. Therefore, you want to access a certain property you can write this way.

The link() function takes three parameters: $scope, element and attributes. The element and attributes arguments are the same as those passed to the compile() function. The $scope parameter is a normal scope object, or when you define isolate scope in the directive definition object, it isolate scope.

The naming of compile() and link() is quite confusing. They must be named after the compilation team. I can see similarities, but a compiler is passed in once and then output. The directive configures HTML elements once and then updates when the $scope object changes later.

The compile() function might be better if it is called create(), init() or configure(). This can express the meaning that this function will only be called once.

The link() function may be better if it is called bind() or render(), and it can better express the meaning. This function will be called when the instruction binds data or rebinates data.

Here is a complete example that demonstrates the use of compile() and link() functions by directives:

<!-- lang: js -->
<div ng-controller="MyController" >
  <userinfo >This will be replaced</userinfo>
</div>
<script>
  myapp = ("myapp", []);
  ('userinfo', function() {
    var directive = {};
     = 'E'; /* restrict this directive to elements */
     = function(element, attributes) {
      ("border", "1px solid #cccccc");
      var linkFunction = function($scope, element, attributes) {
        ("This is the new content: " + $);
        ("background-color", "#ffff00");
      }
      return linkFunction;
    }
    return directive;
  })
  ("MyController", function($scope, $http) {
    $ = "notificationDiv";
    $ = "Jakob";
    $ = function() {
      ("doClick() called");
    }
  });
</script>

The compile() function sets the border of the HTML element. It only executes once, because the compile() function is executed only once.

link() replaces the HTML element content and sets the background color to yellow.

There is no special reason to put the setting border in compile() and the background color in link(). You can throw all operations into compile() or link(). If you put them in compile() they will only be set once (you need them to be constants). If you put it in link(), they will change every time the HTML element is bound to $scope. This is very useful when you want to set the boarder and background color based on the data in $scope.

Set only the link() function

Sometimes your directive may not require compile() . You only need to use link(). In this case, you can directly set the link() function in the directive definition object. The following is a modification to the above example, using only the link function:

<!-- lang: js -->
<div ng-controller="MyController" >
  <userinfo >This will be replaced</userinfo>
</div>
<script>
  myapp = ("myapp", []);
  ('userinfo', function() {
    var directive = {};
     = 'E'; /* restrict this directive to elements */
     = function($scope, element, attributes) {
        ("This is the new content: " + $);
        ("background-color", "#ffff00");
    }
    return directive;
  })
  ("MyController", function($scope, $http) {
    $ = "notificationDiv";
    $ = "Jakob";
    $ = function() {
      ("doClick() called");
    }
  });
</script>

Note that the link() method is exactly the same as the link() returned in the previous example.

Directives to encapsulate elements through Translation

All the examples we have seen so far are replacing the matching element content with the specified content of the directive, whether it is through Javascript or HTML templates. But what if you encounter some content that developers can specify? For example:

<!-- lang: js -->
<mytransclude>This is a transcluded directive {{firstName}}</mytransclude>

An element marked as <mytransclude>, whose parts can be set by the developer. Therefore, this part of HTML should not be replaced by the directive HTML template. We actually want this part of HTML to be processed by AngularJS. This processing is called "translation". 1

In order for AngularJS to put this part of HTML inside the directive, you must set the transclude property of the directive definition object to true. You also need to tell AngularJS which part of the directive HTML template needs to include translated HTML. You can mark the element you want to add translated HTML by inserting the ng-transclude attribute (actually, a directive) into the HTML element of the HTML template.

Here is an AngularJS directive that demonstrates how to use transclusion:

<!-- lang: js -->
<mytransclude>This is a transcluded directive {{firstName}}</mytransclude>
<script>
  myapp = ("myapp", []);
  ('mytransclude', function() {
    var directive = {};
     = 'E'; /* restrict this directive to elements */
     = true;
     = "<div class='myTransclude' ng-transclude></div>";
    return directive;
  });
  ("MyController", function($scope, $http) {
    $ = "Jakob";
  });
</script>

Note the HTML within the <mytransclude> element. This part of the HTML code contains the interpolated directive {{firstName}}. We want AngularJS to handle this part of HTML for us and let the interpolated instructions execute. To achieve this, I set transclude to true in the directive definition object. I also used the ng-transclude property in HTML templates. This property tells AngularJS what elements need to be inserted into translated HTML.

1: To be honest, I didn't understand that definition. It was too difficult to understand, and I was very upset to write the code and didn't output the tutorial. I had to do it myself to make examples. I think this should be the case. Take the target element content as a whole and add it to the tag specified by ng-transclude. I think this processing should be called transcluded. For example, in the example just now (some bugs are corrected by yourself), because = true; , the HTML in the <mytransclude> element is:

<!-- lang: js -->
This is a transcluded directive {{firstName}}

When activate the command 'mytransclude', it will be taken into the template of the 'mytransclude' command and placed in the specified ng-transclude

<!-- lang: js -->
"<div class='myTransclude' ng-transclude></div>"

middle. So the final output result should be:

<!-- lang: js -->
<mytransclude>
  <div class='myTransclude' ng-transclude>
    <span class="ng-scope ng-binding">This is a transcluded directive Jakob</span>
  </div>
</mytransclude>

For more information about AngularJS, readers who are interested in view the topic of this site:AngularJS Introduction and Advanced Tutorial"and"AngularJS MVC architecture summary

I hope this article will be helpful to everyone's AngularJS programming.