How to Change Variables from Outside of a Directive
The way of changing variables depends on the type of scope. See how to change for each type of scope: not inherit, inherit and isolated.
If you use AngularJS directives, you will probably need to change variables inside them. The approach depends on the scope type. As you know, there are 3 types of scope: not inherited (false), inherited (true), and isolated ({}).
Lets see how we can change variables for each type of scope.
1. scope: false (not inherited)
If you omit the scope property or set it to false, the directive does not create a new scope. Instead, it shares the parent scope directly. Because there is no new scope, you can change any variable on the parent scope without any issues.
2. scope: true (inherited)
Setting scope: true means the directive creates a new child scope that prototypically inherits from the parent. It is neither the parent scope nor an isolated scope. Angular creates this child scope and attaches it to the parent.
If you inspect the parent scope, you will see its internal architecture. In the parent scope, you will find $$childHead (the first child scope) and $$childTail (the last child scope). If you have multiple directives, Angular creates child scopes linked via $$nextSibling and $$prevSibling. You can access the first child scope, modify its variables, and traverse the chain to modify others.
The parent scope structure looks like this:
parent scope
$$asyncQueue: Array[0]
$$childHead: $get.e.$new.a
$$asyncQueue: Array[0]
$$childHead: null
$$childTail: null
$$listeners: Object
$$nextSibling: $get.e.$new.a
$$prevSibling: null
$$watchers: null
$id: "004"
$parent: $get.e.$new.a
this: $get.e.$new.a
__proto__: $get.e.$new.a
$$childTail: $get.e.$new.a
$$asyncQueue: Array[0]
$$childHead: null
$$childTail: null
$$listeners: Object
$$nextSibling: null
$$prevSibling: $get.e.$new.a
$$watchers: null
$id: "006"
$parent: $get.e.$new.a
this: $get.e.$new.a
__proto__: $get.e.$new.a
$$listeners: Object
$$nextSibling: null
$$prevSibling: null
$$watchers: null
$id: "003"3. scope: {} (isolated)
In the case of an isolated scope, the directive scope is completely unaware of its parent’s scope. To change variables from outside, you must use scope property bindings:
=(two-way binding): Changes in the parent or directive reflect in both.<(one-way binding): Changes flow only from parent to directive.&(expression binding): Allows calling a function on the parent scope.
Example
Example of changing variables by scope type | JS | W3Docs
<!DOCTYPE html>
<html ng-app="test">
<head>
<title>www.w3docs.com</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script>
angular.module('test',[])
.controller('testCtrl', function($scope){
$scope.message = 'Original';
$scope.changeMessage = function() {
$scope.message = 'Changed from outside';
};
})
.directive('myShared', function(){
return {
restrict: 'EA',
scope: false, // Shares parent scope
template: '<p>{{message}}</p>'
}
})
.directive('myInherited', function(){
return {
restrict: 'EA',
scope: true, // Creates child scope
template: '<p>{{message}}</p>'
}
})
.directive('myIsolated', function(){
return {
restrict: 'EA',
scope: {
message: '=' // Two-way binding
},
template: '<p>{{message}}</p>'
}
})
</script>
</head>
<body>
<div ng-controller="testCtrl">
<button ng-click="changeMessage()">Change Variable</button>
<hr>
<h3>scope: false (shares parent)</h3>
<div my-shared></div>
<hr>
<h3>scope: true (inherits)</h3>
<div my-inherited></div>
<hr>
<h3>scope: {} (isolated)</h3>
<div my-isolated message="message"></div>
</div>
</body>
</html>