Reputation: 829
I just started to study AngularJS and tries to implement customized table directive with the multiple slots transclude. And faced situation that scope not transferred to transclude. There is a lot of solutions in other StackOverflow questions, but all of them works only when in directive template ng-repeat appears for top element, but that is not my case. At least i can't adopt all that solutions.
Simplified version. Directive:
<span>
<div>Some pagination</div>
<div style="display: inline"><input type="text" placeholder="Search"/></div>
<div style="display: inline">Some filters</div>
<table>
<tbody>
<tr ng-repeat="line in lines" ng-transclude="row">
</tr>
</tbody>
</table>
<div>Some pagination again</div>
</span>
Using of directive:
<my-table>
<row>
<td>{{line.col1}}</td>
<td>{{line.col2}}</td>
</row>
</my-table>
Full example with the script on Plunkr: https://plnkr.co/edit/rg43ZdPMGHLBJCTLOoLC
Any advice very appreciated.
Upvotes: 2
Views: 953
Reputation: 23301
The simplest and probably cleanest way to directly reference the $scope
object created by the ng-repeat
in a transcluded template is through the $parent
property:
<my-table>
<td>{{$parent.line.col1}}</td>
<td>{{$parent.line.col2}}</td>
</my-table>
The $parent
property of the $scope
created for a transcluded template points to the $scope
of the target template into which such template is ultimately transcluded (in this case, the ng-repeat
), even though such transcluded $scope
is not a child of the target $scope in the usual sense as a result of the transclusion. See this wonderful blog post for a more complete discussion of this.
Working plunkr: https://plnkr.co/edit/LoqIMiQVZKlTt5epDnZF?p=preview.
Upvotes: 2
Reputation: 5421
i see you don't really need to use attribute
so code look more simple and clean:
<body ng-controller="tableCtrl">
<h1>Table test</h1>
<my-table lines="lines"></my-table>
</body>
your template:
<span>
<div>Some pagination</div>
<div style="display: inline"><input type="text" placeholder="Search"/></div>
<div style="display: inline">Some filters</div>
<table>
<tbody>
<tr ng-repeat="line in lines">
<td>{{line.col1}}</td>
<td>{{line.col2}}</td>
</tr>
</tbody>
</table>
<div>Some pagination again</div>
</span>
and angular directive:
angular.module('myApp', [])
.directive("myTable", function() {
return {
restrict: 'E',
transclude: true,
scope: {
lines:'=lines',
api: '@'
},
templateUrl: "template.html",
};
})
.controller("tableCtrl", ['$scope', function($scope) {
$scope.lines = [
{col1: "testCol1", col2: "testCol2"},
{col1: "testCol11", col2: "testCol21"}
];
}]);
working example in plunkr: https://plnkr.co/edit/iMxRoD0N3sUXqmViHAQh?p=preview
Upvotes: 0
Reputation: 2404
You need to use $transclude function manually and create new child scope for each line. Other than that you need to pass lines to directive if you are using isolated scope (and you are using it). Your linking function should look something like this:
link: function($scope, $element, $attrs, controller, $transclude) {
var tbody = $element.find('tbody');
$scope.$watch('lines', function (lines) {
tbody.empty();
lines.forEach(function (line) {
var childScope = $scope.$new();
childScope.line = line;
$transclude(childScope, function (content) {
tbody.append('<tr>');
tbody.append(content);
tbody.append('</tr>');
}, null, 'row');
});
});
}
Plunker: https://plnkr.co/edit/MLNZOmoQyMazgIpluMqO?p=preview
But that is bad idea anyway, cos it is hard to create table this way. As you can see child of is not elements. You would have to do a little bit of DOM manipulation to make it work.
Upvotes: 1