Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(forms): ensure select[multiple] retains selections #12654

Closed

Conversation

gary-b
Copy link
Contributor

@gary-b gary-b commented Nov 1, 2016

What kind of change does this PR introduce?

[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Other... Please describe:

What is the current behavior?
Closes #12527. The original repro had quite a lot going on, here is a more distilled version Select a few options, then push or pop from the options list.

If you bound an array to select[multiple] via ngModel and subsequently changed the options to select from, the UI would drop any selections that the user had made since.

After options change SelectMultipleControlValueAccessor will read the model again and set the state of the options. The problem was that it didn't keep a reference to the latest model.

What is the new behavior?
SelectMultipleControlValueAccessor maintains an up to date reference to the model. You can now add and remove items from the options and currently selected items will remain selected. Items in the model array that didn't have matching options in the select list will also cause their corresponding options to become selected once added.

Does this PR introduce a breaking change? (check one with "x")

  • Yes
  • No

Whoever looks at this could look at #12519 again too. Ill need to do a little bit of refactoring to the tests when the last one is committed, if they both are accepted that is :P

Copy link
Contributor

@kara kara left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! Looks fine, but requesting minor changes.

`
})
class NgModelSelectMultipleForm {
@Input() selectedCities: any[];
Copy link
Contributor

Choose a reason for hiding this comment

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

The @input decorator is unnecessary - can you remove?

comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCities = [];
detectChangesAndTick();
const select = fixture.debugElement.queryAll(By.css('select'))[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

queryAll doesn't seem necessary here, given that there is only one select element in the test component. Can you switch to query? Then you won't have to look for [0].

const select = fixture.debugElement.queryAll(By.css('select'))[0];
select.nativeElement.value = '1: Object';
dispatchEvent(select.nativeElement, 'change');
detectChangesAndTick();
Copy link
Contributor

Choose a reason for hiding this comment

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

After this change detection run, can you check that the options are selected as you expect? Will make the intent of the test clearer.

detectChangesAndTick();
assertOptionElementSelectedState([false, true, false, false]);
}));
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a test for the 'pop' case?

const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCities = [];
detectChangesAndTick();
Copy link
Contributor

Choose a reason for hiding this comment

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

The test is a bit harder to read because there are no line breaks. Can you add a line break after each logical section? So perhaps here, after the selection is made, and after the new value is pushed?

@kara kara added the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Nov 10, 2016
@vicb
Copy link
Contributor

vicb commented Dec 9, 2016

@gary-b do you have plan to update this PR ?

@gary-b
Copy link
Contributor Author

gary-b commented Dec 11, 2016

Yes, ill work on this and #12519 tomorrow

If you bound an array to select[multiple] via ngModel and subsequently
changed the options to select from, the UI would drop any selections
made since by the user. This was due to
SelectMultipleControlValueAccessor not keeping a reference to the new
model arrays it generated when users interacted with the select control.
Update code to keep the reference.

Closes angular#12527
@gary-b gary-b force-pushed the select-multiple-looses-selection branch from c638a5f to af4328f Compare December 12, 2016 20:36
let fixture: ComponentFixture<NgModelSelectMultipleForm>;
let comp: NgModelSelectMultipleForm;

beforeEach(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used by other tests in #12519

};

const setSelectedCities = (selectedCities: any): void => {
comp.selectedCities = selectedCities;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used by other tests in #12519

@gary-b
Copy link
Contributor Author

gary-b commented Dec 12, 2016

As before, I may need to rebase this again after #12519 is merged as the tests for both introduce the same describe(). They also use the same helper functions.

Copy link
Contributor

@kara kara left a comment

Choose a reason for hiding this comment

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

LGTM

@kara kara added action: merge The PR is ready for merge by the caretaker pr_state: LGTM and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews labels Dec 14, 2016
@vicb vicb closed this in 821b8f0 Dec 14, 2016
vicb pushed a commit that referenced this pull request Dec 15, 2016
If you bound an array to select[multiple] via ngModel and subsequently
changed the options to select from, the UI would drop any selections
made since by the user. This was due to
SelectMultipleControlValueAccessor not keeping a reference to the new
model arrays it generated when users interacted with the select control.
Update code to keep the reference.

Closes #12527
Closes #12654
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: forms cla: yes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

select[multiple] selection clearing when updating options
4 participants