I'm using ui-select plugin and I'm passing ng-model from my controller to a custom directive called richSelect but the ng-model doesn't seemed to get updated on select of any item.
<richselect ng-model="dataModel"></richselect>
Custom directive
app.directive('richselect', ['$compile', function ($compile) {
return {
restrict: 'AE',
scope: {
ngModel: '=' /* Model associated with the object */
},
link: function (scope, element, attrs, ngModel) {
scope.options = [
{
'Value' : 'value1',
'Desc' : 'Value One'
},
{
'Value' : 'value2',
'Desc' : 'Value Two'
}
]
scope.getRichSelectTemplate = function () {
return '<ui-select multiple ng-model="ngModel" theme="bootstrap" ng-disabled="disabled">' +
'{{ngModel}} <ui-select-match placeholder="Select">{{$select.selected.Desc}}</ui-select-match>' +
'<ui-select-choices repeat="option in options | filter: $select.search">' +
'<span ng-bind-html="option.Desc | highlight: $select.search"></span>' +
'</ui-select-choices>' +
'</ui-select>';
}
var linkFn = $compile(scope.getRichSelectTemplate())(scope);
element.append(linkFn);
}
}
}]);
Here, try this. I wasn't exactly sure what format or output you were trying to get, but this gets the selected options passed to the View.
You have to use the ngModel.$setViewValue
in order to change the value of ng-model in the directive in the view. Additionally, to get the value of the ui-select, you need to have ng-model pointed at the options.selected
Then it was just a matter of adding an ng-click
that pointed to a function that updated the view with ngModel.$setViewValue(scope.options.selected
.
Also, I believe you need to `require: 'ngModel' in your directive so you can access the ngModelController.
app.directive('richselect', ['$compile', function ($compile) {
return {
restrict: 'AE',
require: 'ngModel',
scope: {
blah: '=' /* Model associated with the object */
},
link: function (scope, element, attrs, ngModel) {
scope.changer = function() {
ngModel.$setViewValue(scope.options.selected)
console.log(scope.options.selected)
}
scope.options = [
{
'Value' : 'value1',
'Desc' : 'Value One'
},
{
'Value' : 'value2',
'Desc' : 'Value Two'
}
]
scope.getRichSelectTemplate = function () {
return '<ui-select multiple ng-model="options.selected" theme="bootstrap" ng-click="changer()" ng-disabled="disabled">' +
'{{options.selected}} <ui-select-match placeholder="Select">{{$select.selected.Desc}}</ui-select-match>' +
'<ui-select-choices repeat="option in options | filter: $select.search">' +
'<span ng-bind-html="option.Desc | highlight: $select.search"></span>' +
'</ui-select-choices>' +
'</ui-select>';
}
var linkFn = $compile(scope.getRichSelectTemplate())(scope);
element.append(linkFn);
}
}
}]);
EDIT: After a lot of digging and tinkering, per the comment below - getting two-way binding working has proved somewhat elusive. I found it was quite easy to do using the standard ui-select directive, as seen here (modified example code from ui-select), because we can easily get access to the scope of the directive: Standard Directive Demo
I also came across a similar wrapper as the one in the OP, but after playing with it,that one seemed to have the same issue - it's easy to get stuff out, but if you need to push data into the directive it doesn't want to go. Interestingly, in my solution above, I can see that the `scope.options.selected' object actually contains the data, it just never gets down the the scope of the ui-select directive, and thus never allows us to push data in.
After encountering a similar issue with a different wrapper directive in a project I am working on, I figured out how to push data down through the different scopes.
My solution was to modify the ui-select script itself, adding an internal $watch function that checked for a variable in it's $parent
scope. Since the ui-select directive uses scope: true
, it creates a child scope (which, if I am not mistaken, the parent would be the directive in this OP).
Down at the bottom of the link function of the uiSelect directive I added the following watch function:
scope.$watch(function() {
return scope.$parent.myVar;
}, function(newVal) {
$select.selected = newVal;
})
In the link function of our directve here, I added this $watch function:
scope.$watch(function() {
return ngModel.$viewValue;
}, function(newVal) {
scope.myVar = newVal;
})
So what happens here is that if the $viewValue changes (ie, we assign some data from a http service, etc. to the dataModel
binding, the $watch function will catch it and assign it to scope.myVar. The $watch function inside the ui-select script watches scope.$parent.myVar for changes (We are telling it to watch a variable on the scope of it's parent). If it sees any changes it pushes them to $select.selected
- THIS is where ui-select keeps whatever values that have been selected by clicking an item in the dropdown. We simply override that and insert whatever values we want.
First of all dataModel
is a string. Since you defined multiple
the model would be an array.
What's more important is that the uiSelect
directive creates a new scope. That means that ng-model="ngModel"
does no longer point to dataModel
. You effectively destroy the binding.
In your controller make dataModel
an object:
$scope.dataModel = {};
In your directive let the selected values be bound to a property:
return '<ui-select multiple ng-model="ngModel.selection"
Now the the selected values will be bound to dataModel.selection
.
If you don't use the ngModelController
you shouldn't use ng-model
with your directive.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.