ui-select databinding not working in directive - angularjs

I have angular-ui/ui-select working fine as below:
ui-select(multiple="" name="resourceSelector" ng-model="appointmentTemplate.resources")
ui-select-match(placeholder="Select Resources")
span {{$item.name}}
ui-select-choices(repeat="resource in resources | filter: {name:$select.search}")
div {{resource.name}}
When appointmentTemplate.resources is populated like when the view loads, the resource shows as it should in the element.
I have tried to wrap it in a directive (my first). The directive won't show the supplied appointmentTemplate.resources. I can select new ones and save them fine, just not display the existing ones. I have confirmed the data is there using ng-inspector. Here is the directive controller:
angular.module('app').directive('resourceMultiSelector', function(){
return {
restrict: 'E',
scope: {
ngModel: '=',
placeholder: '#'
},
controller: function($scope, zResource, $sce){
zResource.query(function(resources){
$scope.resources = resources;
});
},
templateUrl: "/partials/common/resourceMultiSelector"
};
});
And here is the directive template (in Jade):
ui-select(multiple="" ng-model="$parent.ngModel")
ui-select-match(placeholder="{{placeholder}}")
span {{$item.name}}
ui-select-choices(repeat="resource in resources | filter: {name:$select.search}")
div {{resource.name}}
I use the directive like this:
resource-multi-selector(ng-model="appointmentTemplate.resources" placeholder="Select resources" )
What am I missing here?

Duh. So the objects in the list need to be from the list of choices, not just identical, but the same actual object. Obvious in retrospect I guess :/

Related

Angular Directive vs. Controller function

I have a list of itineraries displayed on a page. Each itinerary has a select button. This select button is a directive.
.directive('itinerarySelectBtn', ['itineraryFactory',
function(itineraryFactory){
return {
restrict: 'E', // defining the container as an element
scope: {
itinerary: '=', // html element we are injecting this directive too
},
replace: true,
templateUrl: '/content/partials/directives/results/results-list.html',
link: function(scope, element, attrs){
element.on('click' , function(){
itineraryFactory.itinerary = scope.itinerary;
});
}
}
}
])
This button does nothing else, other than receive the itinerary object via scope: '=' and then assigns it in my itineraryFactory to the itinerary object. I do this so I can utilise my getter and setter in my itineraryFactory and pull it into my controller.
In my controller:
$scope.itineraries = itineraryFactory.getItinerary();
My question is: Is this overkill, should this be a directive? Alternatively I could just have a $scope.function in my controller and do the same thing. The button could just be part of the ng-repeat that lists the itineraries on the page.
I feel like having a setItinerary() function in my controller would essentially be the same and could be executed via ng-click on the button.
Thoughts?
Regards,
You can do everything in your template.
Say you want to assign $scope.chosenItinerary in your controller from the list in $scope.itineraries
<div ng-repeat="itinerary in itineraries">
<button ng-click="chosenItinerary = itinerary">Pick this one!</button>
</div>

I want to change the value of the template of directive

I define a directive like this:
module.directive("jump", function(html){
var text = html.getHtml();
return{
scope:{},
restrict:"AE",
template: text,
}
});
And I have a service to store the html, like this:
module.factory('html',function(){
var html = "";
return {
setHtml: function(text){
html = text;
},
getHtml: function(){
return html;
}
}
})
I want to change the template value when I enter article pageļ¼Œbecause the detail of every article are different, and I only can get it from API, it's like
<p><a href="#" ng-click="open(\'http://www.facebook.com\')"facebook</a></p>
I want to define a directive for every article to show the detail of article.
But now, when I enter one article page, the directive's template is defined, and if I want to see other article, the template value is the first article's detail.I want to know how to change it.
"Note: All services in Angular are singletons."
(src: https://docs.angularjs.org/guide/providers)
If you need to have the html be different for each instance of your directive, you can't use a singleton that restricts it to a single instance.
Why not just define the template from within the directive? It's a much cleaner pattern that way. Something like this:
directive in use:
<div ng-repeat="foo in dataFromApiThatYouGetFirst">
<jump url="{{foo.url}}" title="{{foo.title}}"></jump>
</div>
directive:
restrict: 'E',
template: '<p>{{vm.title}}</p>',
replace: true,
scope: {
url: '=?',
title: '=?'
},
controllerAs: 'vm',
bindToController: true,

Passing ng-repeat context to child directive

In parts of my application I have used a directive in this format:
<child-directive ng-repeat="item in vm.items"></child-directive>
This one has access to {{item}} from within child-directive without having to do anything.
Now I want to use the same directive along side other directives that all work with the same context data:
<div ng-repeat="item in vm.items">
<child-directive></child-directive>
<other-directive></other-directive>
</div>
The child directive does not need to alter the context data, it only needs the information from inside to display a widget.
I've tried using scope in the directive in this format:
angular
.module('myapp.dashboard')
.directive('childDirective', childDirective);
function childDirective() {
var directive = {
restrict: 'E',
templateUrl: 'client/components/child-directive.ng.html',
controller: 'ChildDirectiveController',
controllerAs: 'vm',
scope: {
item: '='
}
};
return directive;
}
and
<child-directive ng-attr-item="{{item}}"></child-directive>
Within the ng-repeat section. However that just throws an error.
I've also tried ng-bind with no luck.
Any suggestions?
You're using bi-directional scope binding rather than an interpolated property. You can read up on this more in the angular docs
Change your scope object to be:
scope: {
item: '#'
}
OR, change your template to:
<child-directive ng-attr-item="item"></child-directive>

Nested Directives and NgModel

I feel like I'm missing a fundamental concept of Angular directives.
Referring to this Plnkr: http://plnkr.co/edit/WWp9lB6OvxHL8gyBSU5b?p=preview
I have a model of:
{
message: string,
value: number
}
And I have an itemEditor directive to edit that model:
.directive('itemEditor', function() {
return {
replace: true,
templateUrl: 'item.editor.html',
require: 'ngModel',
model: {
item: '=ngModel'
}
};
})
But I want to delegate the editing of value to a custom control:
.directive('valuePicker', function() {
return {
replace: true, // comment this to make it work
templateUrl: 'value.picker.html',
require: 'ngModel',
scope: {
ngModel: '='
},
controller: Controller
};
function Controller($scope, Values) {
$scope.values = Values;
console.log({scope:$scope});
}
})
At current, this code gives the error:
Error: $compile:multidir
Multiple Directive Resource Contention
Commenting the replace: true will allow this code to work. However, I lose the styling instructions from the parent template. I.E: the class form-control is not merged onto the select element.
What is the angular way to make this work?
You are calling value-picker twice here
<value-picker class="form-control" style="width:100%" name="item" value-picker ng-model="item.value"></value-picker>
The value-picker element contains value-picker attribute as well, both being treated as directive which in conflict causing multiple directive error. Remove the attribute value-picker, either call it as element or attribute. Or you can restrict the directive to a specific declaration.
Also remove ng-model from select element of value.picker.html template, which is causing another error:
Multiple directives [ngModel, ngModel] asking for 'ngModel'
So replace: true replaces and appends the current directive attributes to the root level of template element (in your case its select)
Updated Plnkr

Access repeated item inside ng-repeated directive

I'm building a custom directive in AngularJS that I need to be repeated a couple of times. Currently, my page looks like this:
<div my-item ng-repeat="item in items" />
And my directive looks like this:
module.directive('myItem', function() {
return {
restrict: 'A',
replace: true,
scope: { item: '&' },
template: '<div id="item{{$index}}"></div>',
link: function($scope, element, attributes) {
element.append('<div>' + $scope.item.name + '</div>');
}
};
});
However, inside the linking function, $scope.item.name yields undefined. I'm wondering if there is any way I could access the repeated item inside my directive.
If not, what would be my alternatives? Move the ng-repeat inside the directive, maybe?
P.S. I know that you should (generally speaking) not do DOM manipulation this way, but since I might have ~2000 items that would result in 6000 bindings, and I'm afraid that would lead to severe performance issues.
You should pass item as attribute to directive created a sample directive
http://plnkr.co/edit/l5r6zIc7ncT1XldRuB98?p=preview

Resources