Two directives on the same element can not both have isolated scope, but can they both use the same scope isolated from their parent? And can they both use properties bound to the isolated scope?
For example, if I have two directives on an element
<e-directive a-directive prop="parentProp"/>
And one directive defines an isolated scope with a bound property
App.directive('eDirective', function() {
return {
restrict: 'E',
scope: {
localProp: '=prop'
},
...
};
});
Does the other directive get that scope and can it use the bound property?
App.directive('aDirective', function() {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
scope.$watch('localProp', function(newProp, oldProp) {
...
}
},
...
};
});
My initial attempt (pretty much coded as above) failed.
You can not use two structural directives on the same element. You need to wrap your element in another one. It's advised to use ng-container since it wont be rendered in DOM.
By default, directives do not create their own scope; instead they use the scope of their parent, generally a controller (within the scope of which the directive is defined). We can change the default scope of the directive using the scope field of the DDO (Data Definition Object).
Shared scope: directive and controllers share the scope and the data. We cannot pass data explicitly to the directive. 2. Inherited scope: directive inherits the scope of the controller.
I suggest you make use of communicating between the directives' controllers via the require property of the secondary directive. The first directive (e-directive) holds the isolated scope, while the second helper directive (a-directive) has a reference to the first directive and sets properties via functions defined on the first directive. A small sample would be (see plunker):
<!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="[email protected]" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" data-semver="1.2.16"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div e-directive config="parentConfig" a-directive></div>
</body>
</html>
and the javascript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.parentConfig = {};
});
app.controller('ECtrl', function ( $scope ) {
this.setProp = function(newProp){$scope.config.prop = newProp;};
$scope.$watch('config', function(newProp, oldProp) {
console.log(oldProp, newProp);
});
});
app.directive('eDirective', function() {
return {
restrict: 'A',
scope: {
config: '='
},
controller: 'ECtrl',
link: function(scope, element, attrs) {
scope.config.prop ="abc";
}
};
});
app.directive('aDirective', function() {
return {
restrict: 'A',
require: 'eDirective',
link: function(scope, element, attrs,ctrl) {
ctrl.setProp("def");
}
};
});
Instead of an isolate scope, the directives can create a new child scope, which will be shared by both directives. If you need to modify parentProp
in a directive, inject and use $parse
:
<div ng-controller="MyCtrl">
<e-directive a-directive prop="parentProp"></e-directive>
</div>
Javascript:
var app = angular.module('myApp', []);
app.controller('MyCtrl', function($scope) {
$scope.parentProp = { prop1: 'value1' };
});
app.directive('eDirective', function($parse) {
return {
restrict: 'E',
scope: true,
template: '<div>dir template: {{eDirLocalProp}}<br>'
+ '<a href ng-click="eDirChange()">change</a></div>',
link: function(scope, element, attrs) {
scope.eDirProp1 = 'dirPropValue';
var model = $parse(attrs.prop);
scope.eDirLocalProp = model(scope);
scope.eDirChange = function() {
scope.eDirLocalProp.prop1 = "new value";
};
}
};
});
app.directive('aDirective', function() {
return {
scope: true,
link: function postLink(scope, element, attrs) {
scope.$watchCollection(attrs.prop, function(newValue) {
console.log('aDirective', newValue);
});
},
};
});
fiddle
If both directives need to create properties on the new child scope, use some kind of naming convention to prevent name clashes. E.g., scope.eDirProp1 = ...
and scope.aDirProp1 = ...
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With