-
Notifications
You must be signed in to change notification settings - Fork 27.4k
fix(select): keep original selection when using shift to add options … #15676
Conversation
src/ng/directive/select.js
Outdated
// IE and Edge will de-select selected options when you set the selected property again, e.g. | ||
// when you add to the selection via shift+click/UP/DOWN | ||
// Therefore, only set it if necessary | ||
if ((shouldBeSelected && !currentlySelected) || (!shouldBeSelected && currentlySelected)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldBeSelected !== currentlySelected
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I had the feeling this could be simpler :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you swithc to !==
you need to make sure both values are booleans.
(I am not sure about option.selected
. Theoretically it should always be boolean, but you never know especially with older browsers.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't this be tested by directly calling selectCtrl.writeValue
?
src/ng/directive/select.js
Outdated
option.selected = !!value && (includes(value, option.value) || | ||
includes(value, selectCtrl.selectValueMap[option.value])); | ||
var shouldBeSelected = !!value && (includes(value, option.value) || | ||
includes(value, selectCtrl.selectValueMap[option.value])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Align with includes
above.
src/ng/directive/select.js
Outdated
// IE and Edge will de-select selected options when you set the selected property again, e.g. | ||
// when you add to the selection via shift+click/UP/DOWN | ||
// Therefore, only set it if necessary | ||
if ((shouldBeSelected && !currentlySelected) || (!shouldBeSelected && currentlySelected)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you swithc to !==
you need to make sure both values are booleans.
(I am not sure about option.selected
. Theoretically it should always be boolean, but you never know especially with older browsers.)
…in IE/Edge In IE9-11 + Edge, the selected options were previously incorrect under the following circumstances: - at least two options are selected - shift+click or shift+down/up is used to add to the selection (any number of options) In these cases, only the last of the previously selected options and the newly selected options would be selected. The problems seems to be that the render engine gets confused when an option that already has selected = true gets selected = true set again. Note that this is not testable via unit test because it's not possible to simulate click / keyboard events on option elements (the events are delegated to the select element change event), and the problem also doesn't appear when modifying the option elements directly and then using the selectController API. It seems that this only happens when you manipulate the select directly in the user interface. Fixes angular#15675 Closes angular#15676
471c4de
to
14f8ce3
Compare
I tried to test it directly with the selectCtrl API, but this doesn't replicate the bug. It must have something to do with the ui of the select box in IE / Edge. |
Hm. I agree that this is an implementation detail. I'll let you decide if I should add this test or not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"No test" is fine by me.
src/ng/directive/select.js
Outdated
if ((shouldBeSelected && !currentlySelected)) { | ||
setOptionAsSelected(jqLite(option)); | ||
} else if ((!shouldBeSelected && currentlySelected)) { | ||
option.selected = shouldBeSelected; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why we are using option.selected
here, but option.prop('selected', true)
in setOptionAsSelected()
.
Probably doesn't matter, so we should use the same for consistency. In fact, I think it is better to make setOptionSelected()
a helper that can both select and unselect an option and use that whenever needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(BTW, there is a double space before the =
😱
src/ng/directive/select.js
Outdated
function setOptionSelectedStatus(optionEl, value) { | ||
optionEl.prop('selected', value); // needed for IE | ||
if (value) { | ||
optionEl.attr('selected', value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW: .attr('selected', null)
also removes the attribute. So, this could be:
optionEl.prop('selected', value);
optionEl.attr('selected', value || null);
src/ng/directive/select.js
Outdated
* However, screenreaders might react to the selected attribute instead, see | ||
* https://github.com/angular/angular.js/issues/14419 | ||
*/ | ||
optionEl.attr('selected', value || null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I said it works, but do we have tests that the property is actually removed? 😛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you little rascal!
We have the toBeMarkedAsSelected() custom matcher which complains when the selected attr is in the wrong state. And jqlite also removes the attribute when you pass false
and the element is boolean. So I'm going with that.
This helps screen readers identify the selected options, see angular#14419
dcc9b5e
to
0684b39
Compare
…in IE/Edge In IE9-11 + Edge, the selected options were previously incorrect under the following circumstances: - at least two options are selected - shift+click or shift+down/up is used to add to the selection (any number of options) In these cases, only the last of the previously selected options and the newly selected options would be selected. The problems seems to be that the render engine gets confused when an option that already has selected = true gets selected = true set again. Note that this is not testable via unit test because it's not possible to simulate click / keyboard events on option elements (the events are delegated to the select element change event), and the problem also doesn't appear when modifying the option elements directly and then using the selectController API. It seems that this only happens when you manipulate the select directly in the user interface. Fixes #15675 Closes #15676
…in IE/Edge In IE9-11 + Edge, the selected options were previously incorrect under the following circumstances: - at least two options are selected - shift+click or shift+down/up is used to add to the selection (any number of options) In these cases, only the last of the previously selected options and the newly selected options would be selected. The problems seems to be that the render engine gets confused when an option that already has selected = true gets selected = true set again. Note that this is not testable via unit test because it's not possible to simulate click / keyboard events on option elements (the events are delegated to the select element change event), and the problem also doesn't appear when modifying the option elements directly and then using the selectController API. It seems that this only happens when you manipulate the select directly in the user interface. Fixes angular#15675 Closes angular#15676
…in IE/Edge
In IE9-11 + Edge, the selected options were previously incorrect under the following
circumstances:
In these cases, only the last of the previously selected options and the newly selected
options would be selected.
The problems seems to be that the render engine gets confused when an option that
already has selected = true gets selected = true set again.
Note that this is not testable via unit test because it's not possible to simulate
click / keyboard events on option elements (the events are delegated to the select element
change event).
Fixes #15675
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Bugfix
What is the current behavior? (You can also link to an open issue here)
See #15675
Does this PR introduce a breaking change?
No
Please check if the PR fulfills these requirements
[ ] Tests for the changes have been added (for bug fixes / features)[ ] Docs have been added / updated (for bug fixes / features)Other information: