In this tutorial, we will have a look at the advanced concept of AnguarJS custom directive.

If you are new/starter to angular and want to know about the basics of custom directive, read our article AngularJS Custom Directive.

Isolate scope:

Isolated scopes are the scopes which are fully dedicated to a particular custom directive only. It means that the scope inside a directive gets separated from the scope outside.

Directive’s inner scope have been mapped with the outer scope in order to access and use their property.

By default, custom directives access the shared scope of their parents, i.e $scope in controller. In such conditions, we can use custom directive only once within a given scope.

Now, to re-use the directive, we will have to create a new controller.

Let’s understand it through an example.

Suppose, you want to create a directive, which shows different products of different categories. In such situation, we will have to create a separate controller and add properties for each product separately.

And in HTML page, we will have to access these controllers separately using ng-controller directive.

Watch the example code given below.

Note: – In this example, we are displaying and linking four products of our company. These are InkThemes, Aorank, FormGet and MailGet. And we are using controller based on their name. So, don’t be confused if your find these names in the codes.

Example1: Without isolating scope

myController.js

// Application Module
angular.module("myApp", [])
// Controller for inkThemes product
.controller("inkThemeController", ['$scope',function($scope){
$scope.product = {
"product_name" : 'InkThemes',
"product_img_link" : 'inkthemes',
"product_link" :'https://www.inkthemes.com/market/'
};
}])
// Controller for Aorank product
.controller("aorankController", ['$scope',function($scope){
$scope.product = {
"product_name" : 'Aorank',
"product_img_link" : 'aorank',
"product_link" :'https://www.formget.com/market/seo-php-script/'
};
}])
// Controller for MailGet product
.controller("mailgetController", ['$scope',function($scope){
$scope.product = {
"product_name" : 'MailGet',
"product_img_link" : 'mailget',
"product_link" :'https://www.formget.com/mailget/'
};
}])
// Controller for FormGet product
.controller("formgetController", ['$scope',function($scope){
$scope.product = {
"product_name" : 'Formget',
"product_img_link" : 'formget',
"product_link" :'https://www.formget.com/'
};
}])
// Registering custom directive
.directive('myProduct', function(){
return{
templateUrl: 'templates/product_page.html'
};
});

As you can see that we have created different controllers for different products. Reason behind using different controller is that we can access the scope only once for each controller.

index.html

<html ng-app="myApp">
<head>
<title>Custom Directive Example 2</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular.min.js"></script>
<!-- Latest Bootstrap compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="js/myController.js"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container main">
<div class="row">
<h1 class="text-center">AngularJS Isolate Scope Example</h1>
<!-- Access inkThemeController's scope to show inkThemes product properties-->
<div ng-controller="inkThemeController">
<my-product></my-product>
</div>
<!-- Access aorankController's scope to show Aorank product properties-->
<div ng-controller="aorankController">
<my-product></my-product>
</div>
<!-- Access mailgetController's scope to show MailGet product properties-->
<div ng-controller="mailgetController">
<my-product></my-product>
</div>
<!-- Access formgetController's scope to show Formget product properties-->
<div ng-controller="formgetController">
<my-product></my-product>
</div>
</div>
</div>
</body>
</html>

In this file, we accessed all the controllers using ng-controller so that custom directive, myProduct, can use the scope properties only once for each controller to show different products.

product_page.html

This is custom directive’s template which used scope properties and display product in the application. It is included in the custom directive using templateUrl property.

<!-- Layout of each product -->
<div class='product-wrapper'>
<h3 class='text-center'><a href='{{product.product_link}}'>{{product.product_name}}</a></h3>
<div class='product'>
<img ng-src='img/{{product.product_img_link}}.png' alt='{{product_name}}'/>
<div class='clearfix'></div>
<div class='button text-center'>
<a href='{{product.product_link}}' class='btn btn-danger'>Visit Site</a>
</div>
</div>
</div>

Output: –


 Watch output and Download complete code from the link given below.


Finally, we are able to show our products in the application.

But, there is a great risk in these codes. As you can see that currently we have four product and for each product, we have written separate controller which is very lengthy and time-consuming. It can fully mesh up the codes of your application too.

As a solution of these kinds of problems, angular allow you to isolate scopes of your custom directive.

Create Isolate Scopes:

To create an isolated scope in a custom directive, use scope option as given below:

angular.module("myApp", [])

// Registering custom directive
.directive('myProduct', function(){
return{
...
...
scope:{
productInfo : "=showProduct"
}

...
...
};
});

Here, scope option is an object which contains a property for each isolate scope binding. Such as, productInfo : “=showProduct”.

 productInfo : It is the custom directive’s isolate scope property name.

– =showProduct : It tells the compiler to bind showProduct as an attribute to the custom directive.

Here, showProduct is written in camelCase, so in HTML file, you will have to write it in dash-delimited form like show-product.

<my-product show-product></my-product>

Note: – In case, if the attribute name is the same as the value you want to bind to inside the directive’s scope, you can use a shorthand syntax. Such as,

...
scope: {
// same as '=info'
info: '='
},
...

Now, in directives template, you need to access the internal scope of the directive rather than the external scope( as we did in Example1). Such as,

<h3>{{productInfo.product_name}}</h3>
<img ng-src='img/{{productInfo.product_img_link}}.png' alt='{{productInfo.product_name}}'/>
<a href='{{productInfo.product_link}}' class='btn btn-danger'>Visit Site</a>

As above, we have added property, productInfo, in the internal isolated scope of the directive. So, we will have to access prouctInfo in directive’s template rather the ourter scope property, such  as productInfo.product_name, productInfo.product_img_link etc. 

Note: – In case, if you access external scope, like product.product_name, then you will get an undefined values because this template belongs to custom directive and the directive have its own isolated scope.

So, let’s implement the above mentioned concept of isolated scope in an example.

Example2: With isolate scope

myController.js

// Application Module
angular.module("myApp", [])
// Single controller for all product
.controller("productController", ['$scope',function($scope){

// Adding inkthemes as a property to scope
$scope.inkthemes = {
"product_name" : 'InkThemes',
"product_img_link" : 'inkthemes',
"product_link" :'https://www.inkthemes.com/market/'
};

// Adding aorank as a property to scope
$scope.aorank = {
"product_name" : 'Aorank',
"product_img_link" : 'aorank',
"product_link" :'https://www.formget.com/market/seo-php-script/'
};

// Adding mailget as a property to scope
$scope.mailget = {
"product_name" : 'MailGet',
"product_img_link" : 'mailget',
"product_link" :'https://www.formget.com/mailget/'
};

// Adding formget as a property to scope
$scope.formget = {
"product_name" : 'Formget',
"product_img_link" : 'formget',
"product_link" :'https://www.formget.com/'
};
}])
// Registering custom directive
.directive('myProduct', function(){
return{
templateUrl: 'templates/product_page.html',

// Isolated scope for this directive
scope:{
productInfo : "=showProduct"
}
};
});

Here, productController is the only controller in the application which added the different product details in its scope. Whereas directive isolated scope has it’s own property, productInfo, which added showProduct as an attribute to the directive myProduct.

The outer scope’s properties can easily be mapped and accessed by this attribute in the application.

index.html

<html ng-app="myApp">
<head>
<title>Custom Directive Example 2</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular.min.js"></script>
<!-- Latest Bootstrap compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="js/myController.js"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container main" ng-controller="productController">
<div class="row">
<h1 class="text-center">AngularJS Isolate Scope Example</h1>
<div class="col-md-3">

<!-- Directive with showProduct attribute and inkthmes as value -->
<my-product show-product="inkthemes"></my-product>
</div>
<div class="col-md-3">

<!-- Directive with showProduct attribute and aorank as value -->
<my-product show-product="aorank"></my-product>
</div>
<div class="col-md-3">

<!-- Directive with showProduct attribute and mailget as value -->
<my-product show-product="mailget"></my-product>
</div>
<div class="col-md-3">

<!-- Directive with showProduct attribute and formget as value -->
<my-product show-product="formget"></my-product>
</div>
</div>
</div>
</body>
</html>

Here, different properties of external scope (controller’s scope),containing product’s information, are accessed just by using attribute show-product in the directive.

For Example:

<my-product show-product="inkthemes"></my-product>

 Here, showProduct attributes accessed the scope properties of inkthemes product which is available in the external scope. It’s possible because isolated scope mapped with the outer scope and access their properties by passing outer scopes properties though the attribute.

product_page.html

This is directive’s template which accessed the isolated scopes properties of the directive and display different products in the application

<!-- Layout of each product -->
<div class='product-wrapper'>
<h3 class='text-center'><a href='{{productInfo.product_link}}'>{{productInfo.product_name}}</a></h3>
<div class='product'>
<img ng-src='img/{{productInfo.product_img_link}}.png' alt='{{productInfo.product_name}}'/>
<div class='clearfix'></div>
<div class='button text-center'>
<a href='{{productInfo.product_link}}' class='btn btn-danger'>Visit Site</a>
</div>
</div>
</div>

Output:Angular Isolate Scope Example2


Watch output and Download complete code from the link given below.


On comparing Example1 and Example 2 , you can easily find that Example 2 is more organized and easy to implement. We only need to add different products information in the scope which can be easily used within the directive by isolated scope.

However, in Example 1 we need to create separate controllers for each product.

Conclusion:

Hope now you got the concept of isolated scope. Implement it in your custom directives and provides us your feedback from the space given below.

Keep reading our blogs for more interesting blogs on AngularJS.