Reputation: 3322
I want to write directive that will check for available options in the scope and preselect some option if only one item present inside ngOptions.
For now I wrote something like this:
<select id="provider" name="provider" class="form-control"
ng-model="foo.provider"
ng-options="provider.name for provider in providers track by provider.id"
select-first-if-only-one="providers"
required>
<option value="">- Select -</option>
</select>
and my directive:
'use strict';
angular.module('app')
.directive('selectFirstIfOnlyOne', function() {
return {
restrict: 'A',
require: 'select',
link: function(scope, elem, attrs, ctrl) {
scope.$watchCollection(attrs.selectFirstIfOnlyOne, function(values) {
if (angular.isDefined(values) && values.length === 1) {
scope.$evalAsync(function() {
ctrl.ngModelCtrl.$setViewValue(values[0]);
});
}
});
}
};
});
And it works. But I want not to pass array values to directive directly but to take them from ngModel or ngOptions.
I found that SelectController
doesn't provide methods to get all values from <select>
, same for NgModelController
.
Upvotes: 2
Views: 2348
Reputation: 107
Resolved with regex:
http://jsfiddle.net/PxdSP/3206/
Code:
angular.module('myApp')
.directive('selectFirstIfOnlyOne', function () {
return {
restrict: 'A',
require: 'select',
link: function (scope, elem, attrs, ctrl) {
var regex = /in (.+?)(?: |$)/; //Here
var collection = regex.exec(attrs.ngOptions)[1]; // And here
scope.$watchCollection(collection, function (values) {
if (angular.isDefined(values) && values.length === 1) {
scope.$evalAsync(function () {
ctrl.ngModelCtrl.$setViewValue(values[0]);
ctrl.ngModelCtrl.$render();
});
}
});
}
};
});
Upvotes: 1
Reputation: 1405
Something like this fiddle will work if you don't plan on changing the ng-options without reloading the scope.
First off, you can't get information (as far as I'm aware) from ng-options. NgModel has no value yet, that's what you are trying to set with this directive if there is only one option.
You can do it this way sharing the scope with the controller:
<div ng-app="app" ng-controller="cont">
<select id="provider" name="provider" class="form-control"
ng-model="foo.provider"
ng-options="provider.name for provider in providers track by provider.id"
select-first-if-only-one="providers"
required>
<option value="">- Select -</option>
</select>
</div>
angular.module('app', [])
.controller('cont', function($scope) {
$scope.foo = {}
$scope.providers = [{name: 'bob', id: 1}]
})
.directive('selectFirstIfOnlyOne', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
if (scope.providers.length < 2) {
scope.foo.provider = scope.providers[0];
}
}
};
});
If you want to isolate the scope you'll need to pass the information through an isolated scope var:
html select-first-if-only-one="providers.length"
angular.module('app', [])
.controller('cont', function($scope) {
$scope.foo = {}
$scope.providers = [{name: 'bob', id: 1}]
})
.directive('selectFirstIfOnlyOne', function($parse) {
return {
restrict: 'A',
scope: {options: '=selectFirstIfOnlyOne', model: '=ngModel'},
link: function(scope, elem, attrs, ctrl) {
if (scope.options.length < 2) {
scope.model = scope.options[0];
}
}
};
});
Sorry, I was doing this a bit rushed and can change this even further if your still not satisfied.
Upvotes: 3