Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

feat(ngOptions): add support for disabling an option #11017

Closed
wants to merge 1 commit into from

Conversation

sjbarker
Copy link
Contributor

@sjbarker sjbarker commented Feb 9, 2015

This patch adds support for disabling options based on model values. The
"disable when" syntax allows for listening to changes on those model values,
in order to dynamically enable and disable the options.

The changes prevent disabled options from being written to the selectCtrl
from the model. If a disabled selection is present on the model, normal
unknown or empty functionality kicks in.

closes #638

@sjbarker
Copy link
Contributor Author

sjbarker commented Feb 9, 2015

Explanation

The changes in this pull request reflect a long-time reoccurring and widely popular request for the ability to disable options dynamically in ngOptions. This solution accomplishes this feature by adding the disable when syntax to the ng-options directive. All current functionality is retained in select controls.

The solution for model changes reflecting disabled options is to keep the current functionality of "unknown" or "empty" options. Tests have been written to reflect this feature. Consider the following:

scope.selected = '';
scope.options = [ 'a', 'b', 'c', 'd'];
scope.disableOption = function(option) {
  return option === 'b';
}
<select ng-model="selected"
             ng-options="o disable when disableOption(o) for o in options"></select>

-OR-

scope.selected = '';
scope.options = [ 
  {
    name: 'a',
    disabled: false
  },
  {
    name: 'b',
    disabled: false
  },
  {
    name: 'c',
    disabled: false
  },
  {
    name: 'd',
    disabled: false
  }
];
<select ng-model="selected"
             ng-options="o.name disable when o.disabled for o in options"></select>

In either case, if selected becomes a disabled option, then select will render the empty or unknown option. This concurrent with any unknown or invalid option.

Current Issues

Issue #638 has been open for over three years now and is currently on backlog.

Current PR's

There is one current PR (#9854) by @cades that has been rendered obsolete by @petebacondarwin's select.js refactor (408f89d).

@sjbarker
Copy link
Contributor Author

sjbarker commented Feb 9, 2015

@petebacondarwin - Since you recently did the select directive refactor, will you take a quick look at this and pass it around? We have been sitting on this for a really long time and this would provide the functionality without breaking anything; and with room to grow in the future. Thanks!

@cades
Copy link

cades commented Feb 10, 2015

Great job, thanks to your effort and time!
Hope to merge this PR as soon as possible.

@sjbarker
Copy link
Contributor Author

Thanks @cades. You were there first until they refactored the select directive. And thank you for your time and effort as well.

@sjbarker
Copy link
Contributor Author

@pkozlowski-opensource - I figured I would tag you in this since you were attending to the #9854 PR. When you have a moment, will you take a look as well? Thanks.

@sjbarker sjbarker force-pushed the ng-options-disable-by branch 2 times, most recently from 5afa825 to 6e468c8 Compare February 11, 2015 15:48
@petebacondarwin
Copy link
Member

OK, I like this idea, although I think that the syntax sound better with disable when rather than disable by.

Also I am concerned about add to the getWatchables array, which is already a bit of a pain point.

I realised that we can actually optimize this by only including things that are being specified. So for instance, if no disable when clause was provided we would not need to watch this expression. The same for the displayFn which computes the label.

@sjbarker
Copy link
Contributor Author

No problem, @petebacondarwin. Let me get those changes in real quick. I will open an issue for optimizing the getWatchables array and cover it in this commit as well.

//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
// //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@petebacondarwin Here is the syntax change.

if (match[4]) {
var disableWhen = disableWhenFn(scope, locals);
watchedArray.push(disableWhen);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@petebacondarwin - I rebased your perf and mimicked it with the disableWhenFn

@@ -326,7 +350,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
return {
restrict: 'A',
terminal: true,
require: ['select', '?ngModel'],
require: ['select', 'ngModel'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ngModel is still optional here.

This patch adds support for disabling options based on model values. The
"disable when" syntax allows for listening to changes on those model values,
in order to dynamically enable and disable the options.

The changes prevent disabled options from being written to the selectCtrl
from the model. If a disabled selection is present on the model, normal
unknown or empty functionality kicks in.

closes angular#638
@sjbarker
Copy link
Contributor Author

@petebacondarwin I returned the ngModel requirement to optional.

@petebacondarwin
Copy link
Member

I added a few extra tests and merged into master - thanks @sjbarker and @cades !

@sjbarker
Copy link
Contributor Author

Thanks @petebacondarwin! I didn't see that ngModel optional requirement make it in though. Is that ok?

@petebacondarwin
Copy link
Member

Oops

On 18 February 2015 at 13:21, Stephen Barker notifications@github.com
wrote:

Thanks @petebacondarwin https://github.com/petebacondarwin! I didn't
see that ngModel optional requirement make it in though. Is that ok?


Reply to this email directly or view it on GitHub
#11017 (comment).

sjbarker added a commit to sjbarker/angular.js that referenced this pull request Feb 18, 2015
This patch adds support for disabling options based on model values. The
"disable when" syntax allows for listening to changes on those model values,
in order to dynamically enable and disable the options.

The changes prevent disabled options from being written to the selectCtrl
from the model. If a disabled selection is present on the model, normal
unknown or empty functionality kicks in.

Closes angular#638
Closes angular#11017
@sjbarker
Copy link
Contributor Author

@petebacondarwin - f3ae91d here has the commit you just merged with the ngModel require change.

@petebacondarwin
Copy link
Member

Thanks - I fixed that here: ef894c8

@sjbarker
Copy link
Contributor Author

Ok perfect

@IngoVals
Copy link

If the disabling requirements are dynamic and something that was selected becomes disable the value is set to null, could we intercept this event and change it to something else?

@sjbarker
Copy link
Contributor Author

@IngoVals when you say change it to something else, what do you mean?

netman92 pushed a commit to netman92/angular.js that referenced this pull request Aug 8, 2015
This patch adds support for disabling options based on model values. The
"disable when" syntax allows for listening to changes on those model values,
in order to dynamically enable and disable the options.

The changes prevent disabled options from being written to the selectCtrl
from the model. If a disabled selection is present on the model, normal
unknown or empty functionality kicks in.

Closes angular#638
Closes angular#11017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support disabling options in select with ng:options
5 participants