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(select): avoid going into infinite loop under certain conditions #2955

Merged
merged 5 commits into from
Feb 9, 2017

Conversation

crisbeto
Copy link
Member

@crisbeto crisbeto commented Feb 6, 2017

Currently md-select calls writeValue recursively until the QueryList with all of the options is initialized. This usually means 1-2 iterations max, however in certain conditions (e.g. a sibling component throws an error on init) this may not happen and the browser would get thrown into an infinite loop.

This change switches to saving the attempted value assignments in a property and applying it after initialization.

Fixes #2950.

@crisbeto crisbeto requested a review from kara February 6, 2017 19:55
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Feb 6, 2017
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.

Can we also add a test?

this._tempValue = null;
});
}

this._changeSubscription = this.options.changes.subscribe(() => {
Copy link
Contributor

@kara kara Feb 7, 2017

Choose a reason for hiding this comment

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

Given that we are doing the same thing on option changes (i.e. writing the value next tick), I think it might make more sense to just incorporate the logic into the existing stream with rx operatorstartWith(). this._control.value should have the correct value already, so saving a temp version shouldn't be necessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense, I'll rework it. This was already being handled in a similar way on the multiple selection PR.

@crisbeto
Copy link
Member Author

crisbeto commented Feb 7, 2017

Regarding unit tests, this is a little hard to test, because the tests would either crash (if the infinite loop happens) or throw a runtime error (if we avoided the loop). That being said, we already have some tests that will fail if we don't handle the initial value properly.

@kara
Copy link
Contributor

kara commented Feb 7, 2017

@crisbeto How about you use the pattern

expect(() => {
   const fixture = TestBed.createComponent(MyComp);
   fixture.detectChanges();
}).toThrowError(new RegExp(...));

If it passes, we know it's good. If the tests do crash, obviously there's a problem.

@crisbeto
Copy link
Member Author

crisbeto commented Feb 7, 2017

Makes sense, but it probably needs an extra comment about it as well.

@crisbeto
Copy link
Member Author

crisbeto commented Feb 7, 2017

Added the test and used your approach with startWith @kara. Should be good to go. It looks like some positioning-related tests are failing, although they passed locally and shouldn't be related to these changes.

EDIT: Turns out it was a button from another test not being cleaned up.

Currently `md-select` calls `writeValue` recursively until the `QueryList` with all of the options is initialized. This usually means 1-2 iterations max, however in certain conditions (e.g. a sibling component throws an error on init) this may not happen and the browser would get thrown into an infinite loop.

This change switches to saving the attempted value assignments in a property and applying it after initialization.

Fixes angular#2950.
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.

One last nit

@@ -242,7 +244,8 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
ngAfterContentInit() {
this._initKeyManager();
this._resetOptions();
Copy link
Contributor

Choose a reason for hiding this comment

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

You should be able to remove this call now that it's happening again in line 249

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. Should I re-label?

@kara kara removed their assignment Feb 7, 2017
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 pr: lgtm action: merge The PR is ready for merge by the caretaker and removed pr: needs review labels Feb 7, 2017
@kara kara removed the action: merge The PR is ready for merge by the caretaker label Feb 9, 2017
@kara
Copy link
Contributor

kara commented Feb 9, 2017

@crisbeto Can you rebase?

# Conflicts:
#	src/lib/select/select.spec.ts
#	src/lib/select/select.ts
@crisbeto crisbeto added action: merge The PR is ready for merge by the caretaker and removed pr: needs rebase labels Feb 9, 2017
@tinayuangao tinayuangao merged commit 998a583 into angular:master Feb 9, 2017
@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 6, 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 cla: yes PR author has agreed to Google's Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

md-select with ngModel freezes browser if other errors
4 participants