Я хочу написать директиву, которая будет проверять доступные параметры в области и предварительно выбрать какой-либо вариант, если только один элемент присутствует внутри ngOptions.
На данный момент я написал что-то вроде этого:
<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>
и моя директива:
'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]);
});
}
});
}
};
});
И это работает. Но я не хочу передавать значения массива непосредственно директиве, а брать их из ngModel или ngOptions.
Я обнаружил, что SelectController
не предоставляет методы для получения всех значений из <select>
, то же для NgModelController
.
Что-то вроде этой скрипки будет работать, если вы не планируете менять ng-параметры без перезагрузки области.
Во-первых, вы не можете получать информацию (насколько мне известно) из ng-options. NgModel еще не имеет значения, что вы пытаетесь установить с этой директивой, если есть только один параметр.
Вы можете сделать это таким образом, разделяя область действия с контроллером:
<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];
}
}
};
});
Если вы хотите изолировать область действия, вам необходимо передать информацию через изолированную область 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];
}
}
};
});
Извините, я делал это немного поспешно и может изменить это еще дальше, если вы все еще не удовлетворены.
Разрешено с регулярным выражением:
http://jsfiddle.net/PxdSP/3206/
Код:
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();
});
}
});
}
};
});