Passing params to nested directives with isolated scope
Solution 1
I'll repeat what others before me said - that the link
function of firstDirective
is a post-link function that runs after the link
function of secondDirective
, and so scope.numbers
is not yet assigned the object scope.dataFirst.numbers
.
However, a solution that tightly couples two directives via require
seems sub-optimal to me.
Instead, to make sure that a scope property is properly assigned in the parent before inner/child directives run (like secondDirective
, in this case) is to use a pre-link function in the firstDirective
(instead of a post-link)
link: {
pre: function prelink(scope){
console.log('first directive')
console.log(scope)
scope.numbers = scope.dataFirst.numbers;
}
}
Solution 2
My solution to this would be to have the second directive inherit the data object attribute from the first directive.
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.data = {
numbers: {
n1: 'one',
n2: 'two'
},
letters: {
a: 'A',
b: 'B'
}
}
})
.directive('firstDirective', function() {
return {
template: '<div class="first-directive">\
<h2>First Directive</h2>\
{{dataFirst}}\
<div second-directive></div>\
<div second-directive></div>\
</div>',
replace: true,
restrict: 'A',
scope: {
dataFirst: '=firstDirective'
},
controller: function firstDirectiveController($scope) {
return $scope;
},
link: function postLink(scope, element, attrs) {
console.log('first directive')
console.log(scope)
scope.numbers = scope.dataFirst.numbers;
}
};
})
.directive('secondDirective', function() {
return {
template: '<div class="second-directive">\
<h2>Second Directive</h2>\
{{dataSecond}}\
<div class="is-obj">is an object: {{isObj}}</div>\
</div>',
replace: true,
require: '^firstDirective',
link: function postLink(scope, iElement, iAttrs, firstDirectiveController) {
console.log('second directive');
console.log(firstDirectiveController.dataFirst.numbers);
scope.dataSecond = firstDirectiveController.dataFirst.numbers;
scope.isObj = false;
if (angular.isObject(scope.dataSecond)) {
scope.isObj = true;
}
}
};
});
h2 {
padding: 0;
margin: 0;
}
.first-directive {
background: #98FFDA;
color: black;
padding: 10px;
}
.second-directive {
background: #FFA763;
color: white;
padding: 10px;
}
.is-obj {
background: blue;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<h2>MainCtrl</h2>
{{data}}
<div first-directive="data">
</div>
</body>
</html>
cespon
Updated on July 24, 2022Comments
-
cespon almost 2 years
I have an object
data
in theMainCtrl
. This object is used to pass data to directivesfirst-directive
andsecond-directive
. Two-data binding is neccesary in both cases.For
first-directive
, I pass the complete objectdata
but forsecond-directive
I want to passnumbers
object (scope.numbers = scope.dataFirst.numbers
).The problem:
When I do
<div second-directive="dataFirst.numbers"></div>
, and I check ifdataSecond
is an object, it returnstrue
.But when I do
<div second-directive="numbers"></div>
and I check ifdataSecond
is an object, it returnsfalse
.In both cases if I do
console.log(scope)
thescope.dataSecond
property is shown.The question:
Why does this occur and what's the correct way to pass params to directives?
EDIT: The idea is making reusable directives and this implies that they can't depend on others directives.
angular.module('app',[]) .controller('MainCtrl', function($scope) { $scope.data = { numbers: { n1: 'one', n2: 'two' }, letters: { a: 'A', b: 'B' } } }) .directive('firstDirective', function () { return { template: '<div class="first-directive">\ <h2>First Directive</h2>\ {{dataFirst}}\ <div second-directive="dataFirst.numbers"></div>\ <div second-directive="numbers"></div>\ </div>', replace: true, restrict: 'A', scope: { dataFirst: '=firstDirective' }, link: function postLink(scope, element, attrs) { console.log('first directive') console.log(scope) scope.numbers = scope.dataFirst.numbers; } }; }) .directive('secondDirective', function () { return { template: '<div class="second-directive">\ <h2>Second Directive</h2>\ {{dataSecond}}\ <div class="is-obj">is an object: {{isObj}}</div>\ </div>', replace: true, restrict: 'A', scope: { dataSecond: '=secondDirective' }, link: function postLink(scope, element, attrs) { console.log('second directive'); console.log(scope) // <div second-directive="XXXX"></div> // if 'numbers' returns undefined // if 'dataFirst.numbers' returns the object console.log(scope.dataSecond); scope.isObj = false; if(angular.isObject(scope.dataSecond)){ scope.isObj = true; } } }; });
h2 { padding: 0; margin: 0; } .first-directive { background: #98FFDA; color: black; padding: 10px; } .second-directive { background: #FFA763; color: white; padding: 10px; } .is-obj { background: blue; }
<!DOCTYPE html> <html ng-app="app"> <head> <meta charset="utf-8" /> <title>AngularJS Plunker</title> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> </head> <body ng-controller="MainCtrl"> <h2>MainCtrl</h2> {{data}} <div first-directive="data"> </div> <div second-directive="data"> </div> </body> </html>