The problem is that child directive binds to parent however syntax {{name}}
gets ignored by ng-repeat
. What would be the right way achieving this?
HTML (Main/child directive)
<compact-select
no-item-selected-text="Add a Customer"
no-item-selected-icon="fa-user"
search-placeholder="Type a customer name"
cs-model="customer"
cs-items="contacts"
>
<display-item-template>
<span>{{name}}</span>
or
<span>{{item.name}}</span>
</display-item-template>
</compact-select>
Directive
angular.module('core').directive('compactSelect', [function($timeout) {
return {
templateUrl : 'modules/core/views/components/compact-select-tpl.html',
bindToController: true,
transclude: true,
scope: {
noItemSelectedText: '@',
noItemSelectedIcon: '@',
csModel: '=',
csItems: '=csItems'
},
controllerAs : 'ctrl',
controller : function($scope) {
}
};
}]).directive('displayItemTemplate', function($timeout) {
return {
require: '^compactSelect',
restrict: 'E'
}
});
Directive Template (modules/core/views/components/compact-select-tpl.html)
<div class="compact-select-repeater-box" style="" >
<div ng-transclude ng-repeat="item in ctrl.csItems | filter:searchParam" class="compact-select-repeater" ng-class="ctrl.getHighlightedClass(item)" ng-click="ctrl.itemSelected(item)">
<span>{{item.name}}</span>
<span>{{item.id}}</span>
</div>
<div style="position:absolute;bottom:0">
<a href="#">+ Click here to add customer {{ctrl.message}}</a>
</div>
</div>
I can see that
<span>{{item.name}}</span>
<span>{{item.id}}</span>
Gets replaced with
<span></span>
or
<span>{{item.name}}</span>
and not with
<span>{{name}}</span>
or
<span>{{item.name}}</span>
Question: How do I get ng-repeat
to respect html bindings syntax from child directive? Or is there is another way to achieve this?
If i am not wrong, then you are trying to create a list view
such that the template
of the list would be provided by the user, but the methods (click,etc) would already be made available through the directive.
Now, since angular 1.3
, the transcluded scope
is a child of the directive isolated scope
,
so, in your case, if you follow the correct hierarchy, you can access the directive scope
from within the template provided by the user.
Here is your scope hierarchy:
Directive isolated scope
--> ng-repeat new scope for every row
--> transcluded scope
.
so, if you want to access directive scope
from the transcluded scope
,
you would need to do $parent
(for ng-repeat) and then access item.name
, like below:
<display-item-template>
<span>Item Name: {{$parent.item.name}}</span>
</display-item-template>
Also, you don't need the bindings inside your compact-select-tpl
, because you want that content to come from transclusion:
<div class="compact-select-repeater-box" style="" >
<div ng-transclude ng-repeat="item in ctrl.csItems | filter:searchParam"
class="compact-select-repeater"
ng-class="ctrl.getHighlightedClass(item)"
ng-click="ctrl.itemSelected(item)">
<!-- <span>{{item.name}}</span>
<span>{{item.id}}</span> -->
</div>
<div style="position:absolute;bottom:0">
<a href="#">+ Click here to add customer {{ctrl.message}}</a>
</div>
</div>
The displayItemTemplate
directive that you transclude inside the other directive has already it's data interpolated {{name}}
and {{item.name}}
.
If you don't have these variables in the $scope, it will transclude empty strings inside your spans.
Then in your compactSelect
directive, the div that gets transcluded will have it's content overridden.
If you move the displayItemTemplate
directive inside the other directive's template, the repeat will work. (you will need to remove ng(transclude and transclude: true
Fiddle
Additionally, if you use bindToController
, don't put the attributes inside scope.
function compactSelect() {
return {
template : [
'<div class="compact-select-repeater-box" style="" >',
'<div ng-repeat="item in ctrl.csItems | filter:searchParam" class="compact-select-repeater" ng-class="ctrl.getHighlightedClass(item)" ng-click="ctrl.itemSelected(item)">',
'<display-item-template>',
'<span>{{item.name}}</span>',
'</display-item-template>',
'</div>',
'<div style="position:absolute;bottom:0">',
'<a href="#">+ Click here to add customer {{ctrl.message}}</a></div></div>',
].join(''),
bindToController: {
noItemSelectedText: '@',
noItemSelectedIcon: '@',
csItems: '=csItems'
},
scope: {},
controllerAs : 'ctrl',
controller : function($scope) {
}
}
}
function displayItemTemplate() {
return {
require: '^compactSelect',
restrict: 'E'
}
}
function SuperController() {
this.name = "a name";
this.contacts = [{name:"rob"}, {name:"jules"}, {name:"blair"}];
}
angular.module('myApp', []);
angular
.module('myApp')
.controller('SuperController', SuperController)
.directive('compactSelect', compactSelect)
.directive('displayItemTemplate', displayItemTemplate);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="SuperController as s">
<compact-select
no-item-selected-text="Add a Customer"
no-item-selected-icon="fa-user"
search-placeholder="Type a customer name"
cs-items="s.contacts">
</compact-select>
</div>
</div>
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