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

fix(select) ... breaks some selects with required attributes on firefox. #7715

Closed
eendeego opened this issue Jun 5, 2014 · 13 comments
Closed

Comments

@eendeego
Copy link

eendeego commented Jun 5, 2014

The commit dc149de breaks selects with a required attribute and an disabled default empty option, but only on firefox.

Please check this jsbin on both chrome and firefox.

eendeego referenced this issue Jun 5, 2014
In Firefox, hovering over an option in an open select menu updates the selected property of option
elements. This means that when a render is triggered by the digest cycle, and the list of options
is being rendered, the selected properties are reset to the values from the model and the option
hovered over changes. This fix changes the code to only use DOM elements' selected properties in a
comparison when a change event has been fired. Otherwise, the internal new and existing option
arrays are used.

Closes #2448
Closes #5994
Closes #6769
@Narretz
Copy link
Contributor

Narretz commented Jun 20, 2014

It looks like the optional select is also broken on Chrome, because the select has A selected, whereas 'Choose a choice' should be selected

@Narretz Narretz self-assigned this Jun 20, 2014
@Narretz Narretz added this to the 1.3.0-beta.14 milestone Jun 20, 2014
@caitp
Copy link
Contributor

caitp commented Jun 20, 2014

we filed an issue about this with Chromium, actually, because it works as expected in firefox, but differently in chrome --- mostly because that section of html is a bit underspecified.

I haven't kept up with the issues though, don't think I added myself to the CC list

@Narretz
Copy link
Contributor

Narretz commented Jun 20, 2014

Oh, so it's actually correct in Firefox: because the first field is disabled, the second field is automatically selected? But @luismreis says that's broken. So maybe the expectation is that a disabled field can still be preselected (but not user selected), because you don't want to make a selection for the user ... regardless of required state.

@caitp
Copy link
Contributor

caitp commented Jun 20, 2014

the scenario which is broken is sort of hard to explain, it's easiest to just show the fiddle --- it's in one of the issues about this, can't recall OTOH though

@Narretz Narretz removed their assignment Jun 21, 2014
@eendeego
Copy link
Author

@Narretz The scenario is this: you need a select control for something that is required, but you don't want to pre-choose one of the normal options. A way to do this is by having a default value that is disabled, so, the user can choose another one, but not the initial void/empty one.

I prefer the "show disabled option" behaviour, but I understand that it feels a bit broken - maybe I should be using another widget for this.

BTW, I started to have doubts on this being pure browser or angular bejaviour and now there's a new version of the fiddle at (http://jsbin.com/wobod/4). The problem is exactly the same regardless if angular is involved or not.

@jeffbcross
Copy link
Contributor

After some investigation with @ealtenho, I think the only way to satisfy these constraints for a consistent experience in all browsers is to create a new directive (e.g. ngOptionDisabled).

Constraints:

  • Have the disabled option displayed and selected by default
  • Style the disabled option in UA-specific way, indicating that it's not a choice
  • Consider the select element invalid if the disabled element is selected, if the HTML5 required attribute is set
  • Do not allow user to select disabled option (after having selected an enabled option)

The approach would involve setting the disabled property after the option has been added to the document. Setting the disabled attribute on an already-selected, already-rendered option will not de-select it, and will cause it to be styled as a legitimately-disabled option. Presuming the option has the appropriate value (empty string in Chrome, not set in Firefox, who knows in IE...), then the disabled option would still be selected, the select would have a validity.valid value of "false", the UA styling of the option would be correct, and the user could not re-select the option after an enabled option had been selected. We tested this approach in Chrome and Firefox.

Here's the script we were using to test in FF and Chrome:

var select = document.createElement('select');
select.setAttribute('required', true);
var option1 = document.createElement('option');
option1.setAttribute('selected', true);
//if (Chrome) option1.value = ''
select.appendChild(option1);
option1.text = 'One';
var option2 = document.createElement('option');
option2.setAttribute('value', '2');
option2.text = 'Two';
select.appendChild(option2);
document.body.appendChild(select);

//select.validity.valid == false
//Selected option in browser should be 'One'

option1.setAttribute('disabled', true);
//select.validity.valid == false
//Selected option in browser should be 'One'

@caitp interested in your thoughts on this approach

@ealtenho
Copy link
Contributor

ealtenho commented Jul 2, 2014

@jeffbcross @caitp @btford
Another option @jeffbcross and I discussed was examining dc149de which is referenced as the origin of several regressions.

Particularly, we wonder if the alteration in line 540 is a source of error.

Pursuing this strategy, I've been trying to develop a PR:
ealtenho@6adbc1e
However, this currently breaks an e2e test that creates a change based on a blur event.
I'd appreciate any advice.

ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 2, 2014
A previous patch attempted to avoid unnecessary selections
on hover in Firefox by skipping selection changes
when no change event was fired. However, the alteration
in "lastElement[0].selected" to "existingOption.selected"
effectively checked incorrect values. This caused other
select issues, particularly with the disabled attribute.

angular#7715
@caitp
Copy link
Contributor

caitp commented Jul 2, 2014

Basically what the issue came down to was, the existing algorithm was causing a hovered property to be deselected/flicker when frequent digests were happening frequently (if I recall correctly).

I tried a few times to come up with an algorithm which would make each browser happy, but it turned out to be not very easy :( It might actually be easier to just fix the bug in Gecko, and revert the patch here which introduced the regressions.

As it stands, that part of the code is kind of maze-like and very hard to reason about, so I think it's okay to not come up with a workable solution on the first try. I'm sure there's something that could be done about it, but it might be easier to just fix it in C++ instead of JS.

@ealtenho
Copy link
Contributor

ealtenho commented Jul 2, 2014

Thanks @caitp ! I appreciate the advice.

@ealtenho
Copy link
Contributor

ealtenho commented Jul 8, 2014

Currently, our plan to deal with this issue is to

  1. Create a failing test to ensure that reverting dc149de fixes this issue
  2. Revert dc149de
  3. Document why we have decided to revert this commit and explain that ngModelOptions could be used by developers if they have concerns about the digest issue
  4. File an issue with Firefox about the select problem

@ealtenho
Copy link
Contributor

ealtenho commented Jul 9, 2014

@btford
Originally, this issue of a disabled option in a required select being skipped over was opened as a bug created by the fix of a Firefox error in dc149de.

The following tests shows this select box error.

it('should allow the selection of a disabled option as the first element in a required select',
        function() {
          var html = '<select';
          html += ' required>';
          html += '<option value="" disabled>Choose One</option>';
          html += '<option value="1">Option One</option>';
          html += '</select>';

          compile(html);

          document.body.innerHTML = html;

          var options = element.find('option');
          var optionToSelect = options.eq(0);
          expect(optionToSelect.text()).toBe('Choose One');
          expect(optionToSelect.prop('selected')).toBe(true);

          dealoc(element);
    });

It fails in Firefox (but passes in Chrome), documenting this issue.
However, reverting dc149de has no effect on this failing test. It does not appear that dc149de is the cause of this issue.

This appears to be a separate Firefox behavior. Hence a pertinent question now is whether Angular should alter this behavior using something like ngOptionDisabled as @jeffbcross describes.

@lgalfaso
Copy link
Contributor

I would expect for b8ae73e to fix this issue. Can you please check if this issue is present at 1.3.beta15? If it is not, then I can back port this issue to the 1.2.x branch

@IgorMinar IgorMinar assigned ealtenho and unassigned jeffbcross Jul 14, 2014
ealtenho pushed a commit that referenced this issue Jul 15, 2014
A bug in Firefox prevents selecting the first option in a select if that option is disabled
in a required select. The failure of this test documents the operation of this bug.

Related to #7715
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 16, 2014
…render

This reverts commit dc149de.

This commit fixes a bug caused by Firefox updating select.value on hover. However, it
causes other bugs with select including the issue described in angular#7715. This issue causes
selects with a blank disabled option to skip to the second option. A bug has been filed to deal
with the Firefox issue addressed by this commit, and alternate Angular fixes are being investigated.
The test introduced in this commit does test a valid case and should be added back if an Angular
solution to the issue is being pursued.
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 16, 2014
An earlier commit caused an error where the first option of a select would be skipped
over if it had a blank value. This fix adds a test case to identify this case and shows
that reverting the earlier commit causes the behavior to change. In the case of a select with
a blank disabled first option, that option should still be selected.

Relates to angular#7715
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 16, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to angular#7715
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 16, 2014
…render

This reverts commit dc149de.

This commit fixes a bug caused by Firefox updating `select.value` on hover. However, it
causes other bugs with select including the issue described in angular#7715. This issue causes
selects with a blank disabled option to skip to the second option. We filed a bug
with Firefox for the problematic behavior this commit addresses
https://bugzilla.mozilla.org/show_bug.cgi?id=1039047, and alternate Angular fixes are being
investigated. The test introduced in this commit does test a valid case and is therefore not
reverted.
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 16, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to angular#7715
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 17, 2014
…render

This reverts commit dc149de. That commit fixes a bug caused by
Firefox updating `select.value` on hover. However, it
causes other bugs with select including the issue described in angular#7715. This issue details how
selects with a blank disabled option skip to the second option. We filed a bug
with Firefox for the problematic behavior the reverted commit addresses
https://bugzilla.mozilla.org/show_bug.cgi?id=1039047, and alternate Angular fixes are being
investigated. The test introduced in this commit does test a valid case and is therefore not
reverted.

Closes angular#7715 angular#7855
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 17, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to angular#7715
@IgorMinar IgorMinar assigned IgorMinar and unassigned ealtenho Jul 18, 2014
@btford btford modified the milestones: 1.3.0-beta.17, 1.3.0-beta.16 Jul 18, 2014
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Jul 28, 2014
…render

This reverts commit dc149de. That commit fixes a bug caused by
Firefox updating `select.value` on hover. However, it
causes other bugs with select including the issue described in angular#7715. This issue details how
selects with a blank disabled option skip to the second option. We filed a bug
with Firefox for the problematic behavior the reverted commit addresses
https://bugzilla.mozilla.org/show_bug.cgi?id=1039047, and alternate Angular fixes are being
investigated. The test introduced in this commit does test a valid case and is therefore not
reverted.

Closes angular#7715 angular#7855
petebacondarwin pushed a commit to petebacondarwin/angular.js that referenced this issue Jul 28, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to angular#7715
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 28, 2014
…render

This reverts commit dc149de. That commit fixes a bug caused by
Firefox updating `select.value` on hover. However, it
causes other bugs with select including the issue described in angular#7715. This issue details how
selects with a blank disabled option skip to the second option. We filed a bug
with Firefox for the problematic behavior the reverted commit addresses
https://bugzilla.mozilla.org/show_bug.cgi?id=1039047, and alternate Angular fixes are being
investigated.

Closes angular#7715 angular#7855
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 28, 2014
…ith no change event

Commit dc149de was reverted to fix regressions angular#7715 and angular#7855.
This commit introduced this test case and a corresponding fix for preventing the update of the
selected property of an option element on a digest with no change event. Although the previous fix
introduced regressions, the test covers a valid issue and should be included.
ealtenho pushed a commit to ealtenho/angular.js that referenced this issue Jul 28, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to angular#7715
ealtenho pushed a commit that referenced this issue Jul 30, 2014
…ith no change event

Commit dc149de was reverted to fix regressions #7715 and #7855.
This commit introduced this test case and a corresponding fix for preventing the update of the
selected property of an option element on a digest with no change event. Although the previous fix
introduced regressions, the test covers a valid issue and should be included.
ealtenho pushed a commit that referenced this issue Jul 30, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to #7715
petebacondarwin added a commit that referenced this issue Jul 30, 2014
…digest with no change event

The `render()` method was being invoked on every turn of the digest cycle,
which was inadvertently updating the DOM even when a `change` event had
not been triggered.

This change only calls the `render()` method when `ctrl.$render()` is called,
as part of the NgModelController` lifecycle and when the `modelValue` has
significantly changed.

Closes #8221
Closes #7715
ealtenho pushed a commit that referenced this issue Jul 30, 2014
…render

This reverts commit dc149de. That commit fixes a bug caused by
Firefox updating `select.value` on hover. However, it
causes other bugs with select including the issue described in #7715. This issue details how
selects with a blank disabled option skip to the second option. We filed a bug
with Firefox for the problematic behavior the reverted commit addresses
https://bugzilla.mozilla.org/show_bug.cgi?id=1039047, and alternate Angular fixes are being
investigated.

Closes #7715 #7855
ealtenho pushed a commit that referenced this issue Jul 30, 2014
…ith no change event

Commit dc149de was reverted to fix regressions #7715 and #7855.
This commit introduced this test case and a corresponding fix for preventing the update of the
selected property of an option element on a digest with no change event. Although the previous fix
introduced regressions, the test covers a valid issue and should be included.
ealtenho pushed a commit that referenced this issue Jul 30, 2014
An earlier commit dc149de caused an error where the first option of
a select would be skipped over if it had a blank disabled value. These tests demonstrate that with
that commit in place, blank disabled options are skipped in a select. When the commit is reverted,
the correct behavior is seen that the blank disabled option is still selected in both selects
marked with required and those that have optional choices.

Relates to #7715
petebacondarwin added a commit that referenced this issue Jul 30, 2014
…digest with no change event

The `render()` method was being invoked on every turn of the digest cycle,
which was inadvertently updating the DOM even when a `change` event had
not been triggered.

This change only calls the `render()` method when `ctrl.$render()` is called,
as part of the NgModelController` lifecycle and when the `modelValue` has
significantly changed.

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

No branches or pull requests

9 participants