Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/lib/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ describe('MdDialog', () => {

expect(document.activeElement.id)
.toBe('dialog-trigger', 'Expected that the trigger was refocused after dialog close');

document.body.removeChild(button);
}));
});

Expand Down
34 changes: 33 additions & 1 deletion src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ViewChild,
ViewChildren,
ChangeDetectionStrategy,
OnInit,
} from '@angular/core';
import {MdSelectModule} from './index';
import {OverlayContainer} from '../core/overlay/overlay-container';
Expand Down Expand Up @@ -34,6 +35,8 @@ describe('MdSelect', () => {
SelectWithChangeEvent,
CustomSelectAccessor,
CompWithCustomSelect,
SelectWithErrorSibling,
ThrowsErrorOnInit,
BasicSelectOnPush
],
providers: [
Expand Down Expand Up @@ -1239,6 +1242,14 @@ describe('MdSelect', () => {
});
}));

it('should not crash the browser when a sibling throws an error on init', async(() => {
// Note that this test can be considered successful if the error being thrown didn't
// end up crashing the testing setup altogether.
expect(() => {
TestBed.createComponent(SelectWithErrorSibling).detectChanges();
}).toThrowError(new RegExp('Oh no!', 'g'));
}));

});

describe('change event', () => {
Expand Down Expand Up @@ -1281,7 +1292,7 @@ describe('MdSelect', () => {
beforeEach(() => {
fixture = TestBed.createComponent(BasicSelectOnPush);
fixture.detectChanges();
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
trigger = fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement;
});

it('should update the trigger based on the value', () => {
Expand Down Expand Up @@ -1474,6 +1485,27 @@ class CompWithCustomSelect {
@ViewChild(CustomSelectAccessor) customAccessor: CustomSelectAccessor;
}

@Component({
selector: 'select-infinite-loop',
template: `
<md-select [(ngModel)]="value"></md-select>
<throws-error-on-init></throws-error-on-init>
`
})
class SelectWithErrorSibling {
value: string;
}

@Component({
selector: 'throws-error-on-init',
template: ''
})
export class ThrowsErrorOnInit implements OnInit {
ngOnInit() {
throw new Error('Oh no!');
}
}

@Component({
selector: 'basic-select-on-push',
changeDetection: ChangeDetectionStrategy.OnPush,
Expand Down
29 changes: 15 additions & 14 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {ControlValueAccessor, NgControl} from '@angular/forms';
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
import {ConnectedOverlayDirective} from '../core/overlay/overlay-directives';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
import 'rxjs/add/operator/startWith';


/**
* The following style constants are necessary to save here in order
Expand Down Expand Up @@ -243,8 +245,8 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr

ngAfterContentInit() {
this._initKeyManager();
this._resetOptions();
this._changeSubscription = this.options.changes.subscribe(() => {

this._changeSubscription = this.options.changes.startWith(null).subscribe(() => {
this._resetOptions();

if (this._control) {
Expand All @@ -257,8 +259,14 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr

ngOnDestroy() {
this._dropSubscriptions();
this._changeSubscription.unsubscribe();
this._tabSubscription.unsubscribe();

if (this._changeSubscription) {
this._changeSubscription.unsubscribe();
}

if (this._tabSubscription) {
this._tabSubscription.unsubscribe();
}
}

/** Toggles the overlay panel open or closed. */
Expand Down Expand Up @@ -292,17 +300,10 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
* @param value New value to be written to the model.
*/
writeValue(value: any): void {
if (!this.options) {
// In reactive forms, writeValue() will be called synchronously before
// the select's child options have been created. It's necessary to call
// writeValue() again after the options have been created to ensure any
// initial view value is set.
Promise.resolve(null).then(() => this.writeValue(value));
return;
if (this.options) {
this._setSelectionByValue(value);
this._changeDetectorRef.markForCheck();
}

this._setSelectionByValue(value);
this._changeDetectorRef.markForCheck();
}

/**
Expand Down