Reputation: 35970
TL;DR; jsFiddle here.
I want to use two directives (kmOuter
and kmInner
) as nested directives:
<div km-outer>
<div km-inner></div>
<div km-inner></div>
<!-- ... -->
</div>
So I declared them as follows. Please note that inner directive requires outer's controller:
app.directive('kmOuter', function () {
return {
restrict: 'AC',
scope: null,
controller: function ($scope) {
this.childAdded = function () {
console.log('Child added.');
};
}
};
});
app.directive('kmInner', function () {
return {
restrict: 'AC',
require: '^kmOuter',
template: '<div>Lorem ipsum</div>',
link: function (scope, elem, attrs, kmOuterController) {
kmOuterController.childAdded();
}
};
});
That works just fine (.childAdded()
is being called, among others). Now, I want to dynamically insert new instances of inner directive. This action is being triggered from some third, unrelated directive:
app.directive('kmChildAdder', function ($compile) {
return {
restrict: 'AC',
scope: {
target: '@kmChildAdder'
},
link: function (scope, elem) {
console.log(scope);
var target = document.querySelector(scope.target);
angular.element(elem[0]).bind('click', function () {
// Error is here
var newInner = $compile('<div km-inner></div>')(scope)[0];
target.appendChild(newInner);
});
}
};
});
Used like this:
<button km-child-adder="[km-outer]">Add child</button>
But it breaks with the following message:
Error: [$compile:ctreq] Controller 'kmOuter', required by directive 'kmInner',
can't be found!
.childAdded()
isn't called anymore.
How can I fix this? Or maybe this design is itself broken and I should reorganise my code?
Upvotes: 1
Views: 1287
Reputation: 35970
I think I made it, borrowing from @Mobin Skariya's answer.
Key was to $compile
only the inserted element, not all elements:
link: function (scope, elem) {
var target = angular.element(document.querySelector(scope.target));
angular.element(elem[0]).bind('click', function () {
var newInner = angular.element('<div km-inner="param"/>');
target.append(newInner);
scope.$apply(function () {
$compile(newInner)(scope);
});
});
}
I've prepared jsFiddle with example where third, unrelated directive inserts ad compiles inner directive with working, two-way data bindings - you will find it here. Nice thing about it is that third directive (kmChildAdder
) can insert inner directives taking bindings from multiple, separate controllers.
Upvotes: 3
Reputation: 392
Made some edits in your code. Code given in jsFiddle link
link: function (scope, elem) {
console.log(scope);
var target = document.querySelector(scope.target);
angular.element(elem[0]).bind('click', function () {
var newInner = '<div km-inner></div>';
angular.element(target).append(newInner);
$compile(target)(scope)
});
}
Check whether this is what you expect.
Upvotes: 1