transclude: Boolean value that says if the directive should preserve the HTML specified inside the directive element after rendering. The default is false. Let's understand a bit more on transclude.
Example of transclude
Consider a directive called myDirective in an element and that element is enclosing some other content, let's say:
- <div my-directive>
- <button>some button</button>
- <a href="#">and a link</a>
- </div>
If myDirective is using a template, you'll see that the content of <div my-directive> will be replaced by your directive template. So having:
- app.directive('myDirective', function()
- {
- return
- {
- template: '<div class="something"> This is my directive content</div>'
- }
- });
This will result in this render:
- <div class="something"> This is my directive content</div>
Observe here, the content of your original element <div my-directive> will be lost.
- <button>some button</button>
- <a href="#">and a link</a>
So, what if you want to keep your page as in the following:
- <button>some button</button>
- <a href="#">and a link</a>
You'll need something called transclusion.
Include the content from one place into another. So now your directive will look something like this:
- app.directive('myDirective', function()
- {
- return
- {
- transclude: true,
- template: '<div class="something" ng-transclude> This is my directive content</div>'
- }
- });
This would render:
- <div class="something"> This is my directive content
- <button>some button</button>
- <a href="#">and a link</a>
- </div>
Scope: Scope of the directive. It may be the same as the scope of the surrounding element (default or when set to false), inherited from the scope of the surrounding element (set to true) or an isolated scope (set to {}).
By default, a directive gets the parent's scope. But we don't want that in all cases. If we are exposing the parent controller's scope to the directives, they are free to modify the scope properties. In some cases your directive may want to add several properties and functions to the scope that are for internal use only. If we are doing these things to the parent's scope, we are polluting it. So, we have the following two other options:
- A child scope: This scope prototypically inherits the parent's scope.
- An isolated scope: A new scope that does not inherit from the parent and exists on its own.
In Angular, this binding can be done by setting attributes on the directive element in HTML and configuring the scope property in the directive definition object.
Let's explore a few ways of setting up the binding.
Option 1: Use @ for One Way Text Binding
Binds the value of parent scope property (that is always a string) to the local scope. So the value you want to pass in should be wrapped in {{}}.
Option 2: Use = for two-way binding and binds the Parent scope property directly that will be evaluated before being passed in.
Option 3: Use and to Execute functions in the parent scope and binds an expression or method that will be executed in the context of the scope it belongs in.
- app.directive('helloWorld', function()
- {
- return
- {
- scope: {
- Name: '='
- Name: '@'
- Name: '='
- },
-
- };
- });
By default a directive does not create a new scope and uses the parent's scope. But in many cases this is not what we want. If your directive manipulates the parent scope properties heavily and creates new ones, it might pollute the scope. Letting all the directives use the same parent scope is not a good idea because anybody can modify our scope properties. So, the following guidelines may help you choose the right scope for your directive.
Parent Scope (scope: false): This is the default case. If your directive does not manipulate the parent scope properties you might not need a new scope. In this case, using the parent scope is okay.
Child Scope (scope:true): This creates a new child scope for a directive that prototypically inherits from the parent scope. If the properties and functions you set on the scope are not relevant to other directives and the parent, you should probably create a new child scope. With this you also have all the scope properties and functions defined by the parent.
Isolated Scope (scope:{}): This is like a sandbox! You need this if the directive you will build is self-contained and reusable. Your directive might be creating many scope properties and functions that are meant for internal use and should never be seen by the outside world. If this is the case, it's better to have an isolated scope. The isolated scope, as expected, does not inherit the parent scope.
require: A list of directives that the current directive needs. The current directive gets access to controller of the required directive. An object of the controller is passed into the link function of the current directive
controller: Controller for the directive. Can be used to manipulate values on scope or as an API for the current directive or a directive requiring the current directive.
priority: Sets the priority of a directive. The default value is 0. A directive with a higher priority value is executed before a directive with a lower priority.
terminal: Used with priority. If set to true, it stops execution of directives with lower priority. Default is false.
link: A function that contains the core logic of the directive. It is executed after the directive is compiled. Gets access to the scope and element on which the directive is applied (jqLite object attributes) of the element containing the directive and controller object. Generally used to perform DOM manipulation and handling events.
compile: A function that runs before the directive is compiled. Doesn't have access to the scope since the scope is not created yet. Gets an object of the element and attributes. Used to perform the DOM of the directive before the templates are compiled and before the directive is transcluded. It returns an object with the following two link functions:
pre link: Similar to the link function, but it is executed before the directive is compiled. By this time, transclusion is applied. Used rarely. One of the use cases is when a child directive requires data from its parent, the parent directive should set it through its pre-link function. Set data required for its child directives. Safe to attach event handlers to the DOM element. Not safe to access DOM elements belonging to child directives. They're not linked yet.
post link: This is the most commonly used for data binding. Safe to attach event handlers to the DOM element. All children directives are linked, so it's safe to access them. Never set any data required by the child directive here, because the child directive's will be linked already.
Compilation in directives
When the application bootstraps, Angular starts parsing the DOM using the $compile service. This service searches for directives in the mark-up and matches them against registered directives. Once all the directives have been identified, Angular executes their compile functions. As previously said, the compile function returns a link function that is added to the list of link functions to be executed later. This is called the compile phase. If a directive needs to be cloned multiple times (for example ng-repeat), we get a performance benefit since the compile function runs once for the cloned template, but the link function runs for each cloned instance. That's why the compile function does not receive a scope.
After the compile phase is over, next is the linking phase, where the collected link functions are executed one by one. This is where the templates produced by the directives are evaluated against correct scope and are turned into a live DOM that reacts to events.
Let's do some simple samples on custom directives now.