Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<div my-dir attr1="prop1"></div>
<div my-dir attr2="obj.prop2"></div>
<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>
scope.$watch('localName3', function() { ...[?? WHAT TO DO HERE for example?] });
scope.$watch(attrs.attr1, function() { ... });
scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });
var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

@Andy, no don't use $parse with =: fiddle. $parse is only needed with non-isolate scopes.

@collin, great, I'm glad you solved your issue, since I wasn't quite sure how to respond to your other (now deleted) comment.

For 1. and 2. above: normally you specify which parent property the directive needs via an attribute, then $watch it:

For 3. above (isolate scope), watch the name you give the directive property using the @ or = notation:

If you are watching an object property, you'll need to use $parse:

THANK YOU, Mark. It turns out the solution I posted on How to render a partial with variables really does work quite beautifully. What you really needed to link me to was something titled "The nuances of writing HTML and recognizing that your element isn't nested inside the ng-controller that you think it is." Wow... rookie mistake. But this is a useful addition to your other (much longer) answer explaining scopes.

The above link has examples and pictures of all 4 types.

This is a great answer, very thorough. It also illustrates why I simply hate working with AngularJS.

To summarize: the way a directive accesses its parent ($parent) scope depends on the type of scope the directive creates:

You cannot access the scope in the directive's compile function (as mentioned here: https://github.com/angular/angular.js/wiki/Understanding-Directives). You can access the directive's scope in the link function.

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <p>Hello {{user}}!</p>
  <p>directive is watching name and current item</p>
  <table>
    <tr>
      <td>Id:</td>
      <td>
        <input type="text" ng-model="id" />
      </td>
    </tr>
    <tr>
      <td>Name:</td>
      <td>
        <input type="text" ng-model="name" />
      </td>
    </tr>
    <tr>
      <td>Model:</td>
      <td>
        <input type="text" ng-model="model" />
      </td>
    </tr>
  </table>

  <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>

  <p>Directive Contents</p>
  <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>

  <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>

</html>
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>
app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      name: '@',
      currentItem: '=',
      items: '=',
      selectedItems: '=ngModel'
    },
    template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
      'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
      '<option>--</option> </select>',
    link: function(scope, element, attrs) {
      scope.$watchCollection('currentItem', function() {
        console.log(JSON.stringify(scope.currentItem));
      });
      scope.$watch('name', function() {
        console.log(JSON.stringify(scope.name));
      });
    }
  }
})

 app.controller('MainCtrl', function($scope) {
  $scope.user = 'World';

  $scope.addItem = function() {
    $scope.items.push({
      id: $scope.id,
      name: $scope.name,
      model: $scope.model
    });
    $scope.currentItem = {};
    $scope.currentItem.id = $scope.id;
    $scope.currentItem.name = $scope.name;
    $scope.currentItem.model = $scope.model;
  }

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
  }]
});
app.js
index.html
itemfilterTemplate.html
var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=ngModel'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

Option#2. Through Object literal and from directive link/scope

Option#3. Through Function reference and from directive html template

Option#4. Through Function reference and from directive link/scope

Option#5: Through ng-model and two way binding, you can update parent scope variables.

Through Object literal and from directive html template

@YogeshManware: It could be shortened a lot by leaving out the irrelevant stuff like stylesheets, not using lengthy markup, simplifying the examples to not use things like "group by", etc. It would also be very useful with some sort of explanation for each example.

Accessing controller method means accessing a method on parent scope from directive controller/link/scope.

I answered the question with all available alternatives with clear separation. In my opinion, short answers are not always helpful until you have a big picture in front of you.

If the directive is sharing/inheriting the parent scope then it is quite straight forward to just invoke a parent scope method.

If you want to watch other attributes or objects from parent scope, you can do that using $watch and $watchCollection as given below

Little more work is required when you want to access parent scope method from Isolated directive scope.

Note that I used link function in these examples but you can use a directive controller as well based on requirement.

Option#6: Through $watch and $watchCollection It is two way binding for items in all above examples, if items are modified in parent scope, items in directive would also reflect the changes.

There are few options (may be more than listed below) to invoke a parent scope method from isolated directives scope or watch parent scope variables (option#6 specially).

You can always refer AngularJs documentation for detailed explanations about directives.

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


myApp.directive('name', function() {
  return {
    // no scope definition
    link : function(scope, element, attrs, ngModel) {

        scope.vm.func(...)

If you are using ES6 Classes and ControllerAs syntax

See the snippet below and note that vm is the ControllerAs value of the parent Controller as used in the parent HTML

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <p>Hello {{user}}!</p>
  <p>directive is watching name and current item</p>
  <table>
    <tr>
      <td>Id:</td>
      <td>
        <input type="text" ng-model="id" />
      </td>
    </tr>
    <tr>
      <td>Name:</td>
      <td>
        <input type="text" ng-model="name" />
      </td>
    </tr>
    <tr>
      <td>Model:</td>
      <td>
        <input type="text" ng-model="model" />
      </td>
    </tr>
  </table>

  <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>

  <p>Directive Contents</p>
  <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>

  <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>

</html>
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>
app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      name: '@',
      currentItem: '=',
      items: '=',
      selectedItems: '=ngModel'
    },
    template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
      'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
      '<option>--</option> </select>',
    link: function(scope, element, attrs) {
      scope.$watchCollection('currentItem', function() {
        console.log(JSON.stringify(scope.currentItem));
      });
      scope.$watch('name', function() {
        console.log(JSON.stringify(scope.name));
      });
    }
  }
})

 app.controller('MainCtrl', function($scope) {
  $scope.user = 'World';

  $scope.addItem = function() {
    $scope.items.push({
      id: $scope.id,
      name: $scope.name,
      model: $scope.model
    });
    $scope.currentItem = {};
    $scope.currentItem.id = $scope.id;
    $scope.currentItem.name = $scope.name;
    $scope.currentItem.model = $scope.model;
  }

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
  }]
});
app.js
index.html
itemfilterTemplate.html
var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=ngModel'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

Option#2. Through Object literal and from directive link/scope

Option#3. Through Function reference and from directive html template

Option#4. Through Function reference and from directive link/scope

Option#5: Through ng-model and two way binding, you can update parent scope variables.

Through Object literal and from directive html template

@YogeshManware: It could be shortened a lot by leaving out the irrelevant stuff like stylesheets, not using lengthy markup, simplifying the examples to not use things like "group by", etc. It would also be very useful with some sort of explanation for each example.

Accessing controller method means accessing a method on parent scope from directive controller/link/scope.

I answered the question with all available alternatives with clear separation. In my opinion, short answers are not always helpful until you have a big picture in front of you.

If the directive is sharing/inheriting the parent scope then it is quite straight forward to just invoke a parent scope method.

If you want to watch other attributes or objects from parent scope, you can do that using $watch and $watchCollection as given below

Little more work is required when you want to access parent scope method from Isolated directive scope.

Note that I used link function in these examples but you can use a directive controller as well based on requirement.

Option#6: Through $watch and $watchCollection It is two way binding for items in all above examples, if items are modified in parent scope, items in directive would also reflect the changes.

There are few options (may be more than listed below) to invoke a parent scope method from isolated directives scope or watch parent scope variables (option#6 specially).

You can always refer AngularJs documentation for detailed explanations about directives.

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<div my-dir attr1="prop1"></div>
<div my-dir attr2="obj.prop2"></div>
<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>
scope.$watch('localName3', function() { ...[?? WHAT TO DO HERE for example?] });
scope.$watch(attrs.attr1, function() { ... });
scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });
var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

@Andy, no don't use $parse with =: fiddle. $parse is only needed with non-isolate scopes.

@collin, great, I'm glad you solved your issue, since I wasn't quite sure how to respond to your other (now deleted) comment.

For 1. and 2. above: normally you specify which parent property the directive needs via an attribute, then $watch it:

For 3. above (isolate scope), watch the name you give the directive property using the @ or = notation:

If you are watching an object property, you'll need to use $parse:

THANK YOU, Mark. It turns out the solution I posted on How to render a partial with variables really does work quite beautifully. What you really needed to link me to was something titled "The nuances of writing HTML and recognizing that your element isn't nested inside the ng-controller that you think it is." Wow... rookie mistake. But this is a useful addition to your other (much longer) answer explaining scopes.

The above link has examples and pictures of all 4 types.

This is a great answer, very thorough. It also illustrates why I simply hate working with AngularJS.

To summarize: the way a directive accesses its parent ($parent) scope depends on the type of scope the directive creates:

You cannot access the scope in the directive's compile function (as mentioned here: https://github.com/angular/angular.js/wiki/Understanding-Directives). You can access the directive's scope in the link function.

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


scope: false
 transclude: false
$scope.$watch(...

There are a lot of ways how to access parent scope depending on this two options scope& transclude.

Yes, short & sweet, and correct. They seem to share the exact same scope as parent element though... which makes them impossible to re-use in the same scope. jsfiddle.net/collindo/xqytH

and you will have the same scope(with parent element)

many times we need isolated scope when we write reusable component, so the solution is not that simple

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<div my-directive-container="">
    <div my-directive="">
    </div>
</div>
module.directive('myDirectiveContainer', function () {
    return {
        controller: function ($scope) {
            this.scope = $scope;
        }
    };
});

module.directive('myDirective', function () {
    return {
        require: '^myDirectiveContainer',
        link: function (scope, element, attrs, containerController) {
            // use containerController.scope here...
        }
    };
});

Here's a trick I used once: create a "dummy" directive to hold the parent scope and place it somewhere outside the desired directive. Something like:

Maybe not the most graceful solution, but it got the job done.

and then

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<div my-dir attr1="prop1"></div>
<div my-dir attr2="obj.prop2"></div>
<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>
scope.$watch('localName3', function() { ...[?? WHAT TO DO HERE for example?] });
scope.$watch(attrs.attr1, function() { ... });
scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });
var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

@Andy, no don't use $parse with =: fiddle. $parse is only needed with non-isolate scopes.

@collin, great, I'm glad you solved your issue, since I wasn't quite sure how to respond to your other (now deleted) comment.

For 1. and 2. above: normally you specify which parent property the directive needs via an attribute, then $watch it:

For 3. above (isolate scope), watch the name you give the directive property using the @ or = notation:

If you are watching an object property, you'll need to use $parse:

THANK YOU, Mark. It turns out the solution I posted on How to render a partial with variables really does work quite beautifully. What you really needed to link me to was something titled "The nuances of writing HTML and recognizing that your element isn't nested inside the ng-controller that you think it is." Wow... rookie mistake. But this is a useful addition to your other (much longer) answer explaining scopes.

The above link has examples and pictures of all 4 types.

This is a great answer, very thorough. It also illustrates why I simply hate working with AngularJS.

To summarize: the way a directive accesses its parent ($parent) scope depends on the type of scope the directive creates:

You cannot access the scope in the directive's compile function (as mentioned here: https://github.com/angular/angular.js/wiki/Understanding-Directives). You can access the directive's scope in the link function.

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <p>Hello {{user}}!</p>
  <p>directive is watching name and current item</p>
  <table>
    <tr>
      <td>Id:</td>
      <td>
        <input type="text" ng-model="id" />
      </td>
    </tr>
    <tr>
      <td>Name:</td>
      <td>
        <input type="text" ng-model="name" />
      </td>
    </tr>
    <tr>
      <td>Model:</td>
      <td>
        <input type="text" ng-model="model" />
      </td>
    </tr>
  </table>

  <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>

  <p>Directive Contents</p>
  <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>

  <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
</body>

</html>
<select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
 ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
  <option>--</option>
</select>
app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      name: '@',
      currentItem: '=',
      items: '=',
      selectedItems: '=ngModel'
    },
    template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
      'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
      '<option>--</option> </select>',
    link: function(scope, element, attrs) {
      scope.$watchCollection('currentItem', function() {
        console.log(JSON.stringify(scope.currentItem));
      });
      scope.$watch('name', function() {
        console.log(JSON.stringify(scope.name));
      });
    }
  }
})

 app.controller('MainCtrl', function($scope) {
  $scope.user = 'World';

  $scope.addItem = function() {
    $scope.items.push({
      id: $scope.id,
      name: $scope.name,
      model: $scope.model
    });
    $scope.currentItem = {};
    $scope.currentItem.id = $scope.id;
    $scope.currentItem.name = $scope.name;
    $scope.currentItem.model = $scope.model;
  }

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
  }]
});
app.js
index.html
itemfilterTemplate.html
var app = angular.module('plunker', []);

app.directive('sdItemsFilter', function() {
  return {
    restrict: 'E',
    scope: {
      items: '=',
      selectedItems: '=ngModel'
    },
    templateUrl: "itemfilterTemplate.html"
  }
})

app.controller('MainCtrl', function($scope) {
  $scope.name = 'TARS';

  $scope.selectedItems = ["allItems"];

  $scope.items = [{
    "id": "allItems",
    "name": "All Items",
    "order": 0
  }, {
    "id": "CaseItem",
    "name": "Case Item",
    "model": "PredefinedModel"
  }, {
    "id": "Application",
    "name": "Application",
    "model": "Bank"
    }]
});

Option#2. Through Object literal and from directive link/scope

Option#3. Through Function reference and from directive html template

Option#4. Through Function reference and from directive link/scope

Option#5: Through ng-model and two way binding, you can update parent scope variables.

Through Object literal and from directive html template

@YogeshManware: It could be shortened a lot by leaving out the irrelevant stuff like stylesheets, not using lengthy markup, simplifying the examples to not use things like "group by", etc. It would also be very useful with some sort of explanation for each example.

Accessing controller method means accessing a method on parent scope from directive controller/link/scope.

I answered the question with all available alternatives with clear separation. In my opinion, short answers are not always helpful until you have a big picture in front of you.

If the directive is sharing/inheriting the parent scope then it is quite straight forward to just invoke a parent scope method.

If you want to watch other attributes or objects from parent scope, you can do that using $watch and $watchCollection as given below

Little more work is required when you want to access parent scope method from Isolated directive scope.

Note that I used link function in these examples but you can use a directive controller as well based on requirement.

Option#6: Through $watch and $watchCollection It is two way binding for items in all above examples, if items are modified in parent scope, items in directive would also reflect the changes.

There are few options (may be more than listed below) to invoke a parent scope method from isolated directives scope or watch parent scope variables (option#6 specially).

You can always refer AngularJs documentation for detailed explanations about directives.

Note
Rectangle 27 1

How to access parent scope from within a custom directive *with own scope* in AngularJS?


myApp.directive('name', function() {
  return {
    // no scope definition
    link : function(scope, element, attrs, ngModel) {

        scope.vm.func(...)

If you are using ES6 Classes and ControllerAs syntax

See the snippet below and note that vm is the ControllerAs value of the parent Controller as used in the parent HTML

Note