How to use transclusion in the below case. The intention is to use markup in the html (partials) file, than defining it in template (within the directive).
I found a great tree directive here. (source) Original: http://jsfiddle.net/n8dPm/
Instead of defining the template in the directive, I was trying to use a transcluded content. I also updated Angular to 1.2.0.rc2. Updated: http://jsfiddle.net/aZx7B/2/
got below error
TypeError: Property '$transclude' of object [object Object] is not a function
code:
module.directive("tree", function($compile) {
return {
restrict: "E",
transclude: true,
scope: {family: '='},
template:
'<ul>' +
'<li ng-transclude></li>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child"></tree>' +
'</li>' +
'</ul>',
compile: function(tElement, tAttr) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
<div ng-app="myapp">
<div ng-controller="TreeCtrl">
<tree family="family">
<p>{{ family.name }}</p>
</tree>
</div>
</div>
With David's suggestion, made some changes. http://jsfiddle.net/aZx7B/3/
now, it prints, Parent. changing, family
-> treeFamily
didn't work though
The ng-transclude directive facilitates AngularJS to capture everything that is put inside the directive in the markup and use it somewhere in the directive's template.
The ng-transclude directive is used to mark the insertion point for transcluded DOM of the nearest parent that uses transclusion. Use transclusion slot name as the value of ng-transclude or ng-transclude-slot attribute.
transclude - compile the content of the element and make it available to the directive. Typically used with ngTransclude. The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope.
The ng-app directive initializes an AngularJS application. The ng-init directive initializes application data. The ng-model directive binds the value of HTML controls (input, select, textarea) to application data.
You need to output the name of the family in the template as well: http://jsfiddle.net/roadprophet/DsvX6/
module.directive("tree", function($compile) {
return {
restrict: "E",
transclude: true,
scope: {family: '='},
template:
'<ul>' +
'<li ng-transclude></li>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child">{{family.name}}</tree>' +
'</li>' +
'</ul>',
compile: function(tElement, tAttr, transclude) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents, transclude);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
EDIT
You could also simplify by doing this: http://jsfiddle.net/roadprophet/DsvX6/2/
<div ng-app="myapp">
<div ng-controller="TreeCtrl">
<tree family="treeFamily">
</tree>
</div>
</div>
module.directive("tree", function($compile) {
return {
restrict: "E",
transclude: true,
scope: {family: '='},
template:
'<ul>' +
'<li ng-transclude></li>' +
'<p>{{ family.name }}</p>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child"></tree>' +
'</li>' +
'</ul>',
compile: function(tElement, tAttr, transclude) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents, transclude);
}
compiledContents(scope, function(clone, scope) {
iElement.append(clone);
});
};
}
};
});
EDIT Same source of the problem though. No template being passed to the inner tree directive. http://jsfiddle.net/roadprophet/DsvX6/3/
<div ng-app="myapp">
<div ng-controller="TreeCtrl">
<tree family="treeFamily">
<p>{{ family.name }}</p>
</tree>
</div>
</div>
template:
'<ul>' +
'<li ng-transclude></li>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child"><div ng-transclude></div></tree>' +
'</li>' +
'</ul>'
You want to compile the transcluded DOM against the parent scope; you can do this automatically with the injectable $transclude
function in a directive's controller definition:
module.directive("tree", function($compile) {
return {
restrict: "E",
transclude: true,
scope: { family: '=' },
template: '<ul>' +
'<li ng-repeat="child in family.children">' +
'<tree family="child">' +
'<p>{{ child.name }}</p>' +
'</tree>' +
'</li>' +
'</ul>',
controller: function($element, $transclude) {
$transclude(function(e) {
$element.append(e);
});
},
compile: function(tElement, tAttr, transclude) {
var contents = tElement.contents().remove();
var compiledContents;
return function(scope, iElement, iAttr) {
if(!compiledContents) {
compiledContents = $compile(contents);
}
compiledContents(scope, function(clone) {
iElement.append(clone);
});
};
}
};
});
This allows you to use the parent scope property treeFamily
in your root template (also notice the use of child
in the directive's template, above):
<div ng-app="myapp">
<div ng-controller="TreeCtrl">
<tree family="treeFamily">
<p>{{ treeFamily.name }}</p>
</tree>
</div>
</div>
You can see an example here: http://jsfiddle.net/BinaryMuse/UzHeW/
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