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

Fixes to select and ngOptions - "required" validation and behavior with empty / unknown option #15922

Merged
merged 4 commits into from
Apr 21, 2017

Conversation

Narretz
Copy link
Contributor

@Narretz Narretz commented Apr 18, 2017

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
bugfixes

What is the current behavior? (You can also link to an open issue here)

  • (a) when the unknown option is selected and the select is "required", the required error is not set
  • (b) ngOptions: when the model is unmatched and an empty option exists, the empty option is always selected, even if the model is not null / undefined.

What is the new behavior (if this is a feature change)?

  • (a) the error is set
  • (b) the unknown option is selected if the model is not null / undefined

Does this PR introduce a breaking change?
Possibly? For (a), the following situation is possible: The model is programatically set to a value that is no longer in select options, and the select is required. With this patch, the user cannot keep the unmatched value, because of the required error, which considers this value invalid (just realized this, so it's not in the commit message).

For (b), it's unlikely that anyone relied on the fact that the empty option is selected instead of the unmatched option - the fixd behavior was also present in regular select since the beginning.

Please check if the PR fulfills these requirements

Other information:

@Narretz Narretz added this to the 1.6.x milestone Apr 18, 2017
@Narretz Narretz modified the milestones: 1.6.5, 1.6.x Apr 18, 2017
@Narretz Narretz force-pushed the fix-select-ngoptions-required-clean branch from ab0ab63 to 5eff109 Compare April 19, 2017 10:10
@@ -449,12 +449,12 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
if (!multiple) {

selectCtrl.writeValue = function writeNgOptionsValue(value) {
var selectedOption = options.selectValueMap[selectElement.val()];
var selectedOption = selectElement[0].options[selectElement[0].selectedIndex];
Copy link
Member

Choose a reason for hiding this comment

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

Why do you need to skip jqLite/jQuery here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't. I just didn't think to use jQuery here. How do you get the selected option with jquery?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I was just comparing it to the previous code which used options.selectValueMap. Could you explain the change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see. Regular select was using the same technique - getting the option directly from the DOM, so I made it consistent. I don't think there's a huge difference, it just felt right to look at the actual DOM

@petebacondarwin
Copy link
Contributor

I am not sure that (a) is the desired behaviour here. For me required error implies that the input is missing a value. In this scenario it has a value but it is an invalid one. It feels like saying that a number input box has the required error if its value is higher than the maximum allowed.

@Narretz
Copy link
Contributor Author

Narretz commented Apr 19, 2017

@petebacondarwin Hmm ... I implemented this based on the assumptions / opinions found here: #13172 I know, it's been a while :D

I agree that "unknown" is different than "empty" - the latter specifically means the select is "unselected", so setting required error seems solid. For unknown, I guess it depends on the app logic if it fulfills the required condition. The thing is that selects basically only have required validation, because the app is usually responsible for giving the select list.

I don't insist on this change, but I think we should provide a way to manipulate this behavior. The custom isEmpty method can be implemented by a 3rd party directive, but for that we need to expose / document properties of the select controller, mainly ctrl.unknownOption ... and maybe some others. This would obviously put us in a position where we expose more API that we have to maintain :o But it would also allow people to create a different error, e.g. "unmatched value" that is different than "required".

!!selectCtrl.unknownOption.parent().length ||
// When the empty option is selected from the scope, then the viewValue can be different
// than '', and the originalIsEmpty fn will not catch this case
(selectCtrl.hasEmptyOption &&
Copy link
Contributor Author

@Narretz Narretz Apr 19, 2017

Choose a reason for hiding this comment

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

Note that this condition only affects empty option required validation, not unknown option - basically, it's a separate fix - commit message needs to be updated.

@petebacondarwin
Copy link
Contributor

OK, I think exposing some more public API to empower developers is a reasonable goal here.

Narretz added 4 commits April 20, 2017 21:38
…ch empty option

When a regular / ngOptions select has an explicit *empty* option, this option can be selected
by the user and will set the model to `null`. It is also selected when the model is set to
`null` or `undefined`.

When the model is set to a value that does not match any option value, and is also not
`null` or `undefined`, the *unknown* option is inserted and selected - this is an explicit marker
that the select is in an invalid / unknown state, which is different from an allowed empty state.

Previously, regular selects followed this logic, whereas ngOptions selects selected the empty
option in the case described above.

This patch makes the behavior consistent between regular / ngOptions select - the latter will now
insert and select the unknown option. The order of the options has been fixed to unknown -> empty
-> actual options.
@Narretz Narretz force-pushed the fix-select-ngoptions-required-clean branch from 5eff109 to f6021e9 Compare April 20, 2017 19:39
@Narretz
Copy link
Contributor Author

Narretz commented Apr 20, 2017

I've removed the change about required and the unknown option, and expanded on the tests around this behavior. PR is ready to review.
Select API changes will follow in a different PR.

@petebacondarwin
Copy link
Contributor

I'll review tomorrow morning

Copy link
Contributor

@petebacondarwin petebacondarwin left a comment

Choose a reason for hiding this comment

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

Nice work @Narretz - LGTM

@petebacondarwin
Copy link
Contributor

Please merge when you have a moment @Narretz

@Narretz Narretz merged commit ff0e611 into angular:master Apr 21, 2017
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.

4 participants