rand0m86
rand0m86

Reputation: 3322

Angular directive to preselect <select> value if only one option exists in ngOptions

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

Answers (2)

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

Tj Gienger
Tj Gienger

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

Related Questions