Isolated Scopes In Custom Directives

In this article I am explaining Isolated scopes in Custom Directives.

Introduction

In my previous article I explained about "Different Kind of Scopes in Custom Directives", as i promised you previously that I'll explain Isolated Scopes in Custom Directives, so here it is.

Before reading this article I would suggest you to go through the previous article (link above) so that you can know what we are talking about.

I am using previous sample application to explain Isolated Scopes.

Step 1: 

As we had already created a sample application so we can directly go to the controller of Angular. In the controller I am adding a new property into the scope and a new function as well which will be called on button click.

  1. var angularApp = angular.module('angularApp', []);  
  2.   
  3. angularApp.controller('angularController'function ($scope, angularFactory) {  
  4.     $scope.EnterName = "Anubhav";  
  5.     $scope.ProvideName = "Anubhav Chaudhary";  
  6.     $scope.MakeCall = function () {  
  7.         alert("Button Clicked");  
  8.     }  
  9. });  

Step 2: After this it's time to work on the directive where real changes need to be done.

  1. angularApp.directive("customDirective"function () {  
  2.     return {  
  3.         restrict: "E",  
  4.         scope: {  
  5.             text: "@",  
  6.             doublebind: "=",  
  7.             call: "&"  
  8.             },  
  9.         template: "<div>Name you Entered is : {{text}}</div>" +  
  10.             "Provide Your Name : <input type='text' ng-model='text' /> <br /> I am for two way binding : <input type='text' ng-model='doublebind' /> <br /> <input type='button' ng-click='call()' value='Click Me' />"  
  11.         };  
  12. });  

You can see that I had made some changes in scope of this directive. I had provided some symbols and these symbols are known as "Prefix".

Prefix

Prefix are important thing in isolated scopes, prefix assign the values of properties and methods from controller scope to directive scope. If nothing is provided after the prefix then it will search for the attribute which is having the same property name on directive's html element, but if something is provided after the prefix then it will search for that attribute in the directive's html element.

Let's see what does these prefix symbols mean:

@: It is used when we want to provide one way binding i.e. if we change in the controller scope then same changes will be applied in the directive scope but vice versa is not allowed.

= : It's used when we want to provide two way binding i.e. if we change either in controller scope or directive scope then changes will be applied on both.

&: It is used when we want to assign any method from controller scope to directive scope.

Here you can see that I have not provided anything after the prefix, so it'll search for the same property name.

In the template you can see that I have bind the different textbox and button with these properties, so some of them will show one way binding, some will show two way and button will call the method which is defined in controller.

Step 3: It's time to work on the HTML page.

  1. <!DOCTYPE html>  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4.     <title></title>  
  5.     <script src="angular.js"></script>  
  6.     <script src="AngularScript.js"></script>  
  7. </head>  
  8. <body ng-app="angularApp">  
  9.     <form ng-controller="angularController">  
  10.         <fieldset>  
  11.             <legend>I am binding from controller  
  12.             </legend>  
  13.             <input type="text" ng-model="EnterName" />  
  14.             <br />  
  15.             <br />  
  16.             <input type="text" ng-model="ProvideName" />  
  17.         </fieldset>  
  18.   
  19.         <br />  
  20.         <fieldset>  
  21.             <legend>I am binding from directive  
  22.             </legend>  
  23.             <custom-directive text="{{EnterName}}" doublebind="ProvideName" call="MakeCall()"></custom-directive>  
  24.         </fieldset>  
  25.     </form>  
  26.   
  27. </body>  
  28. </html>  

Here you can see that in the custom directive's element I had bind the attributes with the controller's scope, those which needs to be bind for one way binding are bind using {{}}.

Now let's run the application and see the output.


On running the application you can see that first textboxes inside different fieldset are showing the same values because they are bind with same scope property and second textbox inside both fieldset are showing same value because these two are bind with same scope's property.

Now I am changing the value in first textbox.


You can see that changes can be seen in second fieldset controls.

But if I try to change the value in first textbox of second fieldset then corresponding label show the changes not the first textbox of first fieldset.


This is because here only one way binding is provided i.e. from controller to directive.

Now I am changing the value in second textbox.


You can see that second textbox of second fieldset is showing the changed value, but what if I try to change the value from second fieldset?


You can see that changed value is displayed on the second textbox of first fieldset, this is because here two-way binding was provided.

Now I am clicking on the button which was created using the custom directive.


You can see that it has called the method inside controller due to which alert box is displayed.

Till now you have seen that how to provide isolated scopes with no text after the Prefixes. But now I am showing you how to bind when some property name is provided after the prefix.

Step 1: Again I am working on the controller first, here I am adding a new property named "ParentName" and assigned some value to it.

  1. angularApp.controller('angularController'function ($scope, angularFactory) {  
  2.     $scope.EnterName = "Anubhav";  
  3.     $scope.ProvideName = "Anubhav Chaudhary";  
  4.     $scope.ParentName = "Santosh Chaudhary";  
  5.     $scope.MakeCall = function () {  
  6.         alert("Button Clicked");  
  7.     }  
  8. });  

Step 2: After this I am making changes in the directive.

  1. angularApp.directive("customDirective"function () {  
  2.     return {  
  3.         restrict: "E",  
  4.         scope: {  
  5.             text: "@",  
  6.             doublebind: "=",  
  7.             parentname: "=parentName",  
  8.             call: "&"  
  9.             },  
  10.         template: "<div>Name you Entered is : {{text}}</div>" +  
  11.             "Provide Your Name : <input type='text' ng-model='text' /> <br /> I am for two way binding : <input type='text' ng-model='doublebind' /> <br /> Mother Name : <input type='text' ng-model='parentname' /> <br /> <input type='button' ng-click='call()' value='Click Me' />"  
  12.         };  
  13. });  

Here you can see that I had created a new property "parentname" and to this property two-way binding is assigned using the "=" prefix, but after the prefix I had provided "parentName".

In the template also some changes are done, a new textbox is added which is bind to this new property "parentname".

Step 3: Finally change the HTML part.

  1. <body ng-app="angularApp">  
  2.     <form ng-controller="angularController">  
  3.         <fieldset>  
  4.             <legend>I am binding from controller  
  5.             </legend>  
  6.             <input type="text" ng-model="EnterName" />  
  7.             <br />  
  8.             <br />  
  9.             <input type="text" ng-model="ProvideName" />  
  10.             <br />  
  11.             <br />  
  12.             <input type="text" ng-model="ParentName" />  
  13.         </fieldset>  
  14.   
  15.         <br />  
  16.         <fieldset>  
  17.             <legend>I am binding from directive  
  18.             </legend>  
  19.             <custom-directive text="{{EnterName}}" doublebind="ProvideName" parent-name="ParentName" call="MakeCall()"></custom-directive>  
  20.         </fieldset>  
  21.     </form>  
  22.   
  23. </body>  

Here you can see that a custom attribute is added as "parent-name", and to this attribute Controller's scope property is assigned.

One important thing to notice is that in the HTML part "parent-name" is written but in the angular part "parentName" was provided, if you had ever created a directive then you must have already know that why it was done and for others when we are creating any custom directive, then "-" is replaced by capital character.

Now our application is created and it's ready to get executed.

Output: On running the application you will see that all the textboxes are having the values according to properties assigned to them.


Now I am making the changes in textbox which is showing the parent name in second fieldset.


You can see that in the first fieldset changes are shown that's because two way binding was provided.

Similarly you can provide the one way binding and method binding as well.