Angular: Change component template using variables - angularjs

my question is: Is possible to change the component template when the value of a variable changes in the parent controller?
Here there are two ways that I tried to follow:
var topBarTemplateWithButton = [
'<section id="filters">',
'<div class="pull-left">',
'<h1>{{$ctrl.step}}</h1>',
'<div class="pull-left pageActionContainer">',
'<ng-transclude></ng-transclude>',
'</div>',
'</div>',
'</section>'].join(' ')
var topBarTemplateWithoutButton = [
'<section id="filters">',
'<div class="pull-left">',
'<h1>{{$ctrl.step}}</h1>',
'</div>',
'</section>'].join(' ')
myApp.component('topBar', {
bindings: {
step: '<'
},
template: this.templateToUse,
transclude: true,
controller: function() {
var me = this;
me.$onInit = function() {
this.templateToUse = topBarTemplateWithButton;
}
me.$onChanges = function(changes) {
if(changes.step.currentValue != "Projects") {
this.templateToUse = this.topBarTemplateWithoutButton;
}else {
this.templateToUse = topBarTemplateWithButton;
}
}
}
});
and
var topBarTemplateWithButton = [
'<section id="filters">',
'<div class="pull-left">',
'<h1>{{$ctrl.step}}</h1>',
'<div class="pull-left pageActionContainer">',
'<ng-transclude></ng-transclude>',
'</div>',
'</div>',
'</section>'].join(' ')
var topBarTemplateWithoutButton = [
'<section id="filters">',
'<div class="pull-left">',
'<h1>{{$ctrl.step}}</h1>',
'</div>',
'</section>'].join(' ')
myApp.component('topBar', {
bindings: {
step: '<'
},
template: '<div ng-include="$ctrl.templateToUse"/>,
transclude: true,
controller: function() {
var me = this;
me.$onInit = function() {
this.templateToUse = topBarTemplateWithButton;
}
me.$onChanges = function(changes) {
if(changes.step.currentValue != "Projects") {;
this.templateToUse = this.topBarTemplateWithoutButton;
}else {
this.templateToUse = topBarTemplateWithButton;
}
}
}
});
Both these two examples don't work. So it's possible to change the template of this component when the value of step changes? Thank you for your help.

the Template field can be a function that returns a template, and it takes attrs as an injectable. Here's an example that might accomplish what you're looking for.
template: function(attrs) {
"ngInject";
// check for custom attribute and return different template if it's there
},
Important point, however, is that these are uncompiled attributes at this point, because the template hasn't been compiled. It can't be compiled, in fact, until the template is determined. So them attribute you inspect can only be a string literal..

I think this is not the best practice to use two different templates for one component. The main rule is to use one controller with one view. So from this perspective it's better to achieve this behavior is to use ng-switch or ng-if inside component template or even to make two different dumb components - topBarWithButton and topBarWithoutButton. In these both cases you interact with component via bindings. I think this is a bit hacky to use attrs instead of using bindings. Components is not directves so you have to think in terms of components when you build component-based app. I think there are a lot of reasons why you shouldn't use attrs:
You can't change template after it was compiled.
You can't change state of your component.
You keep state in html template.
It's not easy to test this approach.

Related

angular directive scope before return

I need to access a scope variable before entering the return of a directive.
I have a directive which returns a select element with options for each of the trucks.
<tc-vehicle-select label="Truck" selected="activeDailyLog.truck"></tc-vehicle-select>
I need to use the selected value in the directive to put a selected tag on the appropriate option element.
.directive('tcVehicleSelect', function(localStorageService) {
/* Get a list of trucks for the organization and populate a select element for
the user to choose the appropriate truck.
*/
var trucks = localStorageService.get('trucks');
var truckHtml;
for (var i = 0; i < trucks.length; i++) {
var truck = trucks[i];
var injectText;
if(truck.description){
injectText = truck.description
}else{
injectText = 'truck ' + truck.id
}
truckHtml += '<option value="' + truck.id + '">' + injectText + '</option>'
}
return {
scope: {
label: '#',
active: '#'
},
replace: true,
template: '<label class="item item-input item-select">' +
'<div class="input-label">{{label}}</div>' +
'<select ng-model="timeLog.truck"><option value="">None</option>' + truckHtml +
'</select></label>'
};
});
I have everything working in this directive except I'm stuck on setting the selected attribute on the correct element. If I could access the selected variable passed in I would be able to do it by inserting into the truckHtml, but I haven't found examples using that - only using the variables below in the retrun block.
Any ideas?
UPDATE: Also wanted to clarify that the activeDailyLog.truck in the HTML has the correct value I'm looking for.
It makes sense to place your directive's code inside the link function.
To retrieve the passed scope variable inside the directive, use = for two-way binding to the same object.
Code:
.directive('tcVehicleSelect', function(localStorageService) {
/* Get a list of trucks for the organization and populate a select element for
the user to choose the appropriate truck.
*/
return {
scope: {
selected: '='
},
replace: true,
template: '<label class="item item-input item-select">' +
'<div class="input-label">{{label}}</div>' +
'<select ng-model="timeLog.truck"><option value="">None</option>' + truckHtml +
'</select></label>',
link: function(scope, elem, attrs) {
var trucks = localStorageService.get('trucks');
trucks.forEach(function(truck) {
var injectText;
if(truck.description){
injectText = truck.description
} else {
injectText = 'truck ' + truck.id
}
truckHtml += '<option value="' + truck.id + '">' + injectText + '</option>'
}
// Access scope.selected here //
console.log(scope.selected);
}
};
});
Also replaced with Array.forEach() method, as it seemed more relevant in this context!
Internally there are very few differences between directive and a factory. The most important thing here is that directives are cached - your code is only run once and angular will keep reusing its return value every time it needs to use that directive.
That being said, you cannot access scope within directive declaration body - if you could it would be a scope of the first directive and its result would be cached and used for all other places you would use same directive.
I do like the idea of building the options before the return though, assuming you are sure it will not change during the application life (as it will save you from some unnecessary bindings). However, it is usually not true, so I would rather move the whole logic into a compile or even link function:
.directive('tcVehicleSelect', function(localStorageService) {
return {
scope: {
label: '#',
active: '#'
},
replace: true,
template: '<label class="item item-input item-select">' +
'<div class="input-label">{{label}}</div>' +
'<select ng-model="timeLog.truck"><option value="">None</option>'
'</select></label>',
link: function(scope, element) {
var trucks = localStorageService.get('trucks'),
select = element.find('select');
option;
trucks.forEach(function(truck) {
option = angular.element('<option></option>');
option.attr('value', truck.id);
option.html(truck.description || "truck" + truck.id);
if (truck.id === scope.selected.id) {
option.attribute('selected', 'selected');
}
select.append(option);
});
}
};
});

How to make sibling directives communication work( communication between certain specific directive)

All:
Suppose I have two directives( dir1 and dir2) , which are both isolated scope. From some posts, I learnt that I need to use "require" to get scope of the other directive, but there is one question confused me so much:
Suppose I use ng-repeat generated a lot of dir1 and dir2, how do I know in certain dir1, which specific dir2's controller scope is required( cos there are many dir2 and in my understanding, all those scopes in dir2 controller are independent to each other)?
For example:
app.directive("dir1", function(){
var counter = 0;
return {
restrict:"AE",
scope:{},
template: "<button class='dir1_btn'>highlight dir2_"+(couter++)+" </button>",
link:function(scope, EL, attrs){
EL.find("button.dir1_btn").on("click", function(){
// How to let according dir2 know this click?
})
}
}
})
app.directive("dir2", function(){
var counter = 0;
return {
restrict:"AE",
scope:{},
template: "<span class='dir2_area'>This is dir2_"+(couter++)+" </span>",
link:function(scope, EL, attrs){
// Maybe put something here to listening the event passed from dir1?
}
}
})
And the html like( for simple purpose, I just put 2 of each there, actually it will generated by ng-repeat) :
<dir1></dir1>
<dir2></dir2>
<dir1></dir1>
<dir2></dir2>
Consider this just like the switch and light, dir1 is the switch to open(by change background-color) according light (dir2).
In actual project, what I want to do is angularJS directive version
sidemenu and scrollContent, each item in sidemenu is a directive,
click it will make according content(another directive) to auto scroll
to top.
I wonder how to do this? I know this is easy in jQuery, just wondering how to hook this into AngularJS data-driven pattern.
Thanks
The most important thing to note here is that I think you want to use ng-class Since you are creating both directives in an ng-repeat, I assume you are iterating over a list of objects (even if they are two separate ng-repeats, if you iterate over the same list of objects in both it will work. JQuery should not be necessary)? Attach an ngClass object to each object you iterate over, put it on an ng-class attribute in your dir2, then give dir1 access to change it. ngClass provides animation hooks if you want to animate the transition. The rest of my answer may help, though I would like to redo it now that I thought of ng-class. I have to get back to work for now though. I'll watch for feedback and try to answer quickly if you have questions.
I think there are probably a few ways to better accomplish what you are trying to do. It is not clear why both of your directives need to have isolate scopes. As I use angular more I find that though isolating a scope is a powerful technique, it is best to avoid over using it.
As for the require directive property, this post explains how to make directives communicate via their controllers very well.
I have two possible suggestions for you.
Make it one directive
Why can't you just put the templates into one?
Or if as I assume there is some reason they need to be separate, you could consider just sharing an object between them.
<div ng-repeat='obj in sharedDirObjs'>
<dir1 shared-dir-obj='obj'></dir1>
<dir2 shared-dir-obj='obj'></dir2>
</div>
app.controller('ctrl', function() {
$scope.sharedDirObjs = [obj1, obj2, obj3]
});
app.directive("dir1", function(){
var counter = 0;
return {
restrict:"AE",
scope:{sharedDirObj : '='},
template: "<button class='dir1_btn' ng-click='clickFn()'>highlight dir2_"+(couter++)+" </button>",
link:function(scope, EL, attrs){
var dir1vars...
scope.clickFn = function(){
// dir1 logic...
scope.sharedDirObj.dir2.clickFn(dir1vars...);
};
}
}})
app.directive("dir2", function(){
var counter = 0;
return {
restrict:"AE",
scope:{sharedDirObj : '='},
template: "<span class='dir2_area'>This is dir2_"+(couter++)+" </span>",
link:function(scope, EL, attrs){
scope.sharedDirObj.dir2 = {};
scope.sharedDirObj.dir2.clickFn(dir1vars...) {
// access to dir2 vars
};
}
}})
Similarly, you could create a service that holds an array of objects that are shared by injecting the service and indexed using the $index from the ng-repeat, or you could use an id system as PSL suggests. Note that the solution I describe above could work with isolate scope, or without it using scope.$eval(attr.sharedObj); on either or both of your directives. The answer to this question provides a solid runthrough of when and why to use isolated scope. In any case it would likely be best not to pipe functions through a shared object as I am showing above, and timing issues would need to be dealt with. Better would be to store properties on the object and set a scope.$watch on them in your dir2.
You may have to use some sort of strategy. Some kind of identifier hook up. Clearly you cannot use require(to require the controller of a directive and you don't have any also it can only look up to ancestors or itself not siblings). For example you could add an id attribute and a for attribute and target the element with a selection based on specific attribute value and fire an event. With this position of related element does not matter.
Your directive could look like:
<dir1 dir-for="id1"></dir1>
<dir2 dir-id="id1"></dir2>
<dir1 dir-for="id2"></dir1>
<dir2 dir-id="id2"></dir2>
and simple implementation:
.directive("dir1", function($document) {
var counter = 0;
return {
restrict: "AE",
scope: {
dirFor: '#'
},
template: "<button class='dir1_btn' ng-click='handleClick()'>highlight dir2_({{dirFor}}) </button>",
link: function(scope, EL, attrs) {
var $target = angular.element(
$document[0].querySelector('[dir-id="' + scope.dirFor + '"]'))
.contents().scope();
var clicked = false;
scope.handleClick = function() {
clicked = !clicked;
targetScope.$broadcast("SWITCH_CLICKED", clicked);
}
scope.$on('$destory',function() {
$target = null;
}
}
}
})
app.directive("dir2", function() {
var counter = 0;
return {
restrict: "AE",
scope: {
dirId: '#'
},
template: "<span class='dir2_area' ng-class=\"{true:'on', false:'off'}[status]\">This is dir2_{{dirId}}</span>",
link: function(scope, EL, attrs) {
console.log(scope.$id);
scope.status = false;
scope.$on('SWITCH_CLICKED', function(e, data) {
scope.status = data;
});
}
}
});
Demo
var app = angular.module('app', []).controller('ctrl', angular.noop);
app.directive("dir1", function($document) {
var counter = 0;
return {
restrict: "AE",
scope: {
dirFor: '#'
},
template: "<button class='dir1_btn' ng-click='handleClick()'>highlight dir2_({{dirFor}}) </button>",
link: function(scope, EL, attrs) {
var $target = angular.element($document[0].querySelector('[dir-id="' + scope.dirFor + '"]')).contents();
var clicked = false;
scope.handleClick = function() {
clicked = !clicked;
$target.scope().$broadcast("SWITCH_CLICKED", clicked);
}
scope.$on('$destroy',function() {
$target = null;
});
}
}
})
app.directive("dir2", function() {
var counter = 0;
return {
restrict: "AE",
scope: {
dirId: '#'
},
template: "<span class='dir2_area' ng-class=\"{true:'on', false:'off'}[status]\">This is dir2_{{dirId}}</span>",
link: function(scope, EL, attrs) {
scope.status = false;
scope.$on('SWITCH_CLICKED', function(e, data) {
scope.status = data;
});
}
}
})
.on{
color:green;
}
.off{
color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<dir1 dir-for="id1"></dir1>
<dir2 dir-id="id1"></dir2>
<dir1 dir-for="id2"></dir1>
<dir2 dir-id="id2"></dir2>
</div>
I have used $document[0].querySelector('[dir-id="' + scope.dirFor + '"]')).contents().scope() to get hold of the scope, similarly you could do .controller to get hold of the controller instance as well. Current example is doing an absolute selection(with document), you could as well make it relative.

Recursive angular directive with large data

I have a angular directive to generate nested list structure. However when i get large data, browser gets stuck & is very slow. If it was only ng-repeat i could have used limitTo but this is a recursive template. Any suggestion please.
http://jsfiddle.net/L97o5swa/14/
treeModule.directive('tmTree', function() {
return {
restrict: 'E', // tells Angular to apply this to only html tag that is <tree>
replace: true, // tells Angular to replace <tree> by the whole template
scope: {
t: '=src',
fetchChildren: '&fetchChildren',
selectNode : '&selectNode' // create an isolated scope variable 't' and pass 'src' to it.
},
controller : function($scope){
console.log('aaa');
},
template: '<ul><branch ng-repeat="c in t.children" src="c" fetch-children="fetchChildren()" select-Node="selectNode({node :child})" ng-class="c.expandChildren ? \'\':\'collapsed\' "></branch></ul>' ,
link: function(scope, element, attrs) {
}
};
});
treeModule.directive('branch', function($compile) {
return {
restrict: 'E', // tells Angular to apply this to only html tag that is <branch>
replace: true, // tells Angular to replace <branch> by the whole template
scope: {
b: '=src',
fetchChildren: '&fetchChildren', // create an isolated scope variable 'b' and pass 'src' to it.
selectNode : '&selectNode'
},
controller : function($scope,$element){
} ,
template: '<li class="treeNode"><div class="wholerow"></div><span id="chevron-right" class="glyphicon glyphicon-chevron-right" ></span><a ng-click="selectNode({child : b})">{{ b.text }}</a></li>',
link: function(scope, element, attrs) {
//// Check if there are any children, otherwise we'll have infinite execution
var has_children = angular.isArray(scope.b.children);
var parent = scope.b;
//// Manipulate HTML in DOM
if (has_children) {
element.append($compile( '<tm-tree src="b" fetch-children="fetchChildren()" select-Node="selectNode({node:child})" ></tm-tree>')(scope) );
// recompile Angular because of manual appending
//$compile(element.contents())(scope);
}
var chevronRight = angular.element(element.children()[1]);
chevronRight.on('click',function(event) {
event.stopPropagation();
chevronRight.toggleClass('glyphicon-chevron-right');
chevronRight.toggleClass('glyphicon-chevron-down');
if(has_children){
element.toggleClass('collapsed');
if(scope.b.children.length == 0) {
}
}
});
}
};
});
Hard to tell based on the piece of code you posted. But my initial instinct is that you shouldn't be using so many jqLite references like element and append. You should handle more of this functionality within the template itself using ngRepeat (ie. if (has_children) { element.append...) and ngClick (ie. chevronRight.on('click'...). jqLite operations are expensive.

AngularJS : after isolating scope and binding to a parentFunction, how to pass parameters to this parentFunction?

I'm trying very hard to understand scopes in AngularJS and am running into problems.
I've created a simple "comments" application that
has an input box for publishing a comment (text + 'Reply' button) [this is working fine]
clicking 'Reply' button unhides another input box for publishing a reply (with a 'PublishReply' button)
clicking 'PublishReply' button, publishes the reply below the original comment and also indents it.
I generate comments within 'commentsDirective' using ng-repeat and embed a 'replyDirective' within each ng-repeat. I'm able to bind the parent scope's functions from the child directive's isolated scope, but I'm just not able to pass the arguments to this function.
Again, I think, a scope related problem is preventing me to hide/unhide the 'replyDirective' from the on-click of 'Reply' button.
Grateful for your help.
Here is the code in plunker: http://plnkr.co/edit/5AmlbOh6iEPby9K2LJDE?p=preview
<body ng-app="comments">
<div ng-controller="mainController">
<div class="publishComment"><input type="text" ng-model="contentForPublishing"/><button ng-click="publishComment(null, 0, contentForPublishing)">Publish Comment</button></div>
<comments-directive></comments-directive>
</div>
</body>
<script>
angular.module('comments', [])
.controller('mainController', function($scope) {
$scope.comments = [
{ id: 1, parentId: 0, content:'first comment'},
{ id: 2, parentId: 0, content:'second comment'}
];
$scope.publishComment = function (commentId, commentParentId, contentForPublishing){
if (commentId === null) {commentId = $scope.comments.length + 1;} // this (commentId === null) is sent only from the publishComments and not from publishReply
$scope.comments.push( { id: commentId, parentId:commentParentId, content:contentForPublishing } );
$scope.contentForPublishing = "";
}
$scope.replyWidgetVisible = false;
$scope.showReplyWidget = function() {
$scope.replyWidgetVisible = true;
}
})
.directive('commentsDirective', function() {
return {
restrict: 'E',
// template: '<div id="{{comment.id}}" class="commentWrapper" ng-class="{{ {true: '', false: 'indentLeft'}[{{comment.parentId}} === 0] }}" ng-repeat="comment in comments">' +
template: '<div id="{{comment.id}}" class="commentWrapper" ng-repeat="comment in comments">' +
'id: {{comment.id}} parentId: {{comment.parentId}}<br>>> {{comment.content}}<br>' +
'<button class="reply" ng-click="showReplyWidget()">Reply</button>' +
// '<reply-directive publish-reply="publishComment()" ng-show="{{replyWidgetVisible}}" reply-widget-visible="replyWidgetVisible"></reply-directive>' +
'<reply-directive publish-reply="publishComment()" comments-array="comments"></reply-directive>' +
'</div>'
};
})
.directive('replyDirective', function() {
return {
restrict: 'E',
scope: {
publishReply: '&',
commentsArray: '=',
replyWidgetVisible: '='
},
template: '<div class="publishComment"><input type="text" ng-model="contentForPublishing"/><button ng-click="publishReply(5, 1, contentForPublishing)">Publish Reply</button></div>'
};
});
</script>
Basically you need to "fetch" the publishComment function, since with publish-reply="publishComment()" you are telling Angular to call publishComment without any arguments, regardless of the arguments you are passing on your isolated scope. So, to actually reach the publishComment function (and not only the predefined executing function), so you can pass in arguments, you need to:
.directive('commentsDirective', function() {
return {
restrict: 'E',
template: '<div id="{{comment.id}}" class="commentWrapper" ng-repeat="comment in comments">' +
'id: {{comment.id}} parentId: {{comment.parentId}}<br>>> {{comment.content}}<br>' +
'<button class="reply" ng-click="showReplyWidget()">Reply</button>' +
'<reply-directive publish-reply="publishReply()" comments-array="comments"></reply-directive>' +
'</div>',
link: function(scope){
scope.publishReply = function(){
return scope.publishComment;
}
}
};
})
.directive('replyDirective', function() {
return {
restrict: 'E',
scope: {
publishReply: '&',
commentsArray: '=',
replyWidgetVisible: '='
},
template: '<div class="publishComment"><input type="text" ng-model="contentForPublishing"/><button ng-click="publishReply(5, 1, contentForPublishing)">Publish Reply</button></div>',
link: function(scope) {
scope.publishReply = scope.publishReply();
}
};
});
Think it like if you were doing: (function(){ return scope.publishComment(); })(5, 1, contentForPublishing);
Doing a "get reference to function" parent scope binding is mainly useful when the passed function is mutable. for example, my-cool-function="doThis()" and on another part of your app my-cool-function="doThat()". they exist so you can reuse the same directive in many situations, which isn't the case here.
A much simpler way would to $emit a publish event from your isolated scope and catch it in your comments directive. Or create a scope with true so you can access, in your newly created child scope, the function directly from the parent.
See updated plnkr in here http://plnkr.co/edit/nOWwFJ35XRXaIoxNPlW4?p=preview
Here is the plnkr showing how to keep just one reply box opened (you can keep as many open if you wish) http://plnkr.co/edit/za16eHPzltGLjK5ra1Vb?p=preview (see the revision before it for a widget state for each comment)

Directive with <select ng-options> and indirection

I have several multi-selects on a page, each with a bit of logic that fills that multi-select from the server, and I want to wrap each one up into a Directive.
Before trying to wrap these into Directives, I built each as such:
index.html
<select name="groups" ng-model="inputs.groups" ng-change="groupsChanged()" ng-options="g for g in allgroups" multiple></select>
controllers.js
In the first pass, I do my $http calls from here. Yes, I know, not best practices, but I wanted to prove that this works to myself first.
$scope.loadSelect = function(_url) {
$http({
url: _url,
method: 'POST',
data: $scope.inputs,
model: 'all' + _url
}).success(function(data, status, headers, config) {
$scope[config.model] = data;
});
};
// Fill groups
$scope.loadSelect('groups');
// When groups change, reload other select fields that depend on groups
$scope.groupsChanged = function() {
$scope.loadSelect('categories');
$scope.loadSelect('actions');
}
Now I want to migrate this to a Directive. I see two major challenges:
1.) How do I encapsulate the entire set of options (e.g. what is now the "allgroups" model) into the Directive?
2.) Based on initial experiments, I tried to physically build the <select/> into the template, but realized that I have to manipulate the DOM to physically replace name, ng-model, and ng-options. That lead me to the compile attribute, but a.) that feels wrong and b.) setting <select ng-options="x for x in allgroups" /> doesn't actually repeat after it's been inserted into the DOM. Using compile doesn't feel right; what's the right way to approach this?
Here is my first attempt at the Directive looks like this. It doesn't really work, and I think I'm going about it incorrectly:
index.html
<dimension ng-model="inputs.users" alloptions-model="allusers">Users</dimension>
directives.js
directive('dimension', function() {
return {
restrict: 'E',
scope: {
ngModel: '=',
alloptionsModel: '='
},
template:
'<div>' +
'<label ng-transclude></label>' +
'<fieldset>' +
'<div class="form-group">' +
'<select ng-model="{{ngModel}}" ng-options="x for x in {{alloptionsModel}}" multiple class="form-control"></select>' +
'</div>' +
'</fieldset>' +
'</div>',
replace: true,
transclude: true
};
});
Clearly I haven't even gotten to the server load part yet, but I plan to roll that into a controller in the Directive, with the actual $http call in a service.
I feel like I'm moving down the wrong track. If you have suggestions on how to realign, please help!
The main problem with your directive is that you can't use mustache binding in ngModel and ngOptions directive because they are evaluated directly. You can directly bind to the scoped property (ngModel and alloptionsModel):
directive('dimension', function() {
return {
restrict: 'E',
scope: {
ngModel: '=',
alloptionsModel: '='
},
template:
'<div>' +
'<label ng-transclude></label>' +
'<fieldset>' +
'<div class="form-group">' +
'<select ng-model="ngModel" ng-options="x for x in alloptionsModel" multiple class="form-control"></select>' +
'</div>' +
'</fieldset>' +
'</div>',
replace: true,
transclude: true
};
});
See this plunkr for a working example.
Edit
As for the compile route, there is nothing wrong with it. It is useful when you need to dynamically create a template which will clearly be your case when you will get to the select's item template.
compile: function(tElement, tAttrs) {
var select = tElement.find('select'),
value = tAttrs.value ? 'x.' + tAttrs.value : 'x',
label = tAttrs.label ? 'x.' + tAttrs.label : 'x',
ngOptions = value + ' as ' + label + ' for x in alloptionsModel';
select.attr('ng-options', ngOptions);
}
// In the HTML file
<dimension ng-model="inputs.users"
alloptions-model="allusers"
label="name">
Users
</dimension>
I've updated the plunkr with the compile function.

Resources