20

I have a html select option

<select>
    <option ng-repeat="field in filter.fields" value="{{field.id}}">{{field.name}}</option>
</select>

which I am iterating from ng-repeat , I want to disable option on basis of a filed selectable like

<select>
    <option ng-repeat="field in filter.fields" {field.selectable==true?enable:disable} value="{{field.id}}">{{field.name}}</option>
 </select>

How can I achieve this with angular?

m59
  • 43,214
  • 14
  • 119
  • 136
Satish Sharma
  • 3,284
  • 9
  • 38
  • 51
  • Ordinarily to make a select list with angularjs you're using the ng-options directive though I don't know that it has built in support for disabling options (you may need to copy/tweak the source) the other directive to be aware of that might help with the way you're trying to handle this is ng-disabled http://docs.angularjs.org/api/ng.directive:ngDisabled – shaunhusain Sep 10 '13 at 15:21
  • Are you intentionally not binding the value of the `select` input to a model? – bibs Sep 10 '13 at 15:30
  • possible duplicate of [ng-options with disabled rows](http://stackoverflow.com/questions/16202254/ng-options-with-disabled-rows) – m59 Sep 10 '13 at 15:32
  • Not a duplicate in my opinion, since the way by which ` – Amy Pellegrini Jul 01 '16 at 15:35

3 Answers3

29

Assuming you have a structure like this:

  $scope.filter = {
    fields: [
      {id: 1, name: "a", selectable: false},
      {id: 2, name: "asdf", selectable: true},
      {id: 3, name: "qwet", selectable: false},
      {id: 4, name: "qnjew", selectable: true},
      {id: 5, name: "asdjf", selectable: false}
    ]
  };

This should work for you:

  <select>
    <option ng-repeat="field in filter.fields" ng-disabled="field.selectable" value="{{field.id}}">{{field.name}}</option>
  </select>
  • I'd still recommend you have a look at m59's answer. The problems with my solution that he's highlighting might come back to bite you. –  Sep 11 '13 at 06:20
10

While the ng-disabled attribute will technically work, you are likely to encounter bugs when using ng-repeat on options. This is a well known issue and is exactly the reason that the angular team created ng-options. There is not yet an angular implementation for using ng-options and ng-disabled together, but Alec LaLonde created this custom directive that you can add in and use. See the issue forum here: https://github.com/angular/angular.js/issues/638 and the jsfiddle from that post.

angular.module('myApp', [])
.directive('optionsDisabled', [ '$parse', function($parse) {
        var disableOptions = function($scope, attr, $element, data, fnDisableIfTrue) {
            $element.find('option:not([value="?"])').each(function(i, e) { //1
                var locals = {};
                locals[attr] = data[i];
                $(this).attr('disabled', fnDisableIfTrue($scope, locals));
            });
        };

        return {
            priority: 0,
            require: 'ngModel',
            link: function($scope, $element, attributes) { //2
                var expElements = attributes.optionsDisabled.match(/^\s*(.+)\s+for\s+(.+)\s+in\s+(.+)?\s*/),
                    attrToWatch = expElements[3],
                    fnDisableIfTrue = $parse(expElements[1]);
                $scope.$watch(attrToWatch, function(newValue, oldValue) {
                    if (!newValue) return;

                    disableOptions($scope, expElements[2], $element, newValue, fnDisableIfTrue);
                }, true);

                $scope.$watch(attributes.ngModel, function(newValue, oldValue) { //3
                    var disabledOptions = $parse(attrToWatch)($scope);
                    if (!newValue) return;

                    disableOptions($scope, expElements[2], $element, disabledOptions, fnDisableIfTrue);
                });
            }
        };
    }
]);
//1 refresh the disabled options in the select element
//2 parse expression and build array of disabled options
//3 handle model updates properly

function OptionsController($scope) {
    $scope.ports = [{name: 'http', isinuse: true},
                    {name: 'test', isinuse: false}];

    $scope.selectedport = 'test';
}
XDS
  • 3,786
  • 2
  • 36
  • 56
m59
  • 43,214
  • 14
  • 119
  • 136
  • 1
    I have updated the referenced JS Fiddle to work with JQLite: [link](http://jsfiddle.net/7HXUH/) – HANiS Apr 04 '14 at 10:49
4

This is actually a fairly old question. In the later version of Angular (angular 1.4+) you have the ngOptions directive. Here is the link:-

https://docs.angularjs.org/api/ng/directive/ngOptions

There is now a syntax for handling this case:-

label disable when disable for value in array track by trackexpr

I thought I would put this in in case someone else visits this page.

user1545858
  • 725
  • 4
  • 21