fix(select): view not updating when using OnPush detection strategy (#2894)

Fixes the select's view not being updated when the value is set through a component that has its change detection set to `OnPush`.

Fixes #2663.
Fixes #2269.
This commit is contained in:
Kristiyan Kostadinov
2017-02-09 19:31:55 +01:00
committed by tinayuangao
parent 1a89a08f1c
commit 3bcb7c3314
2 changed files with 60 additions and 4 deletions
+56 -2
View File
@@ -1,6 +1,13 @@
import {TestBed, async, ComponentFixture, fakeAsync, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {Component, DebugElement, QueryList, ViewChild, ViewChildren} from '@angular/core';
import {
Component,
DebugElement,
QueryList,
ViewChild,
ViewChildren,
ChangeDetectionStrategy,
} from '@angular/core';
import {MdSelectModule} from './index';
import {OverlayContainer} from '../core/overlay/overlay-container';
import {MdSelect} from './select';
@@ -26,7 +33,8 @@ describe('MdSelect', () => {
SelectInitWithoutOptions,
SelectWithChangeEvent,
CustomSelectAccessor,
CompWithCustomSelect
CompWithCustomSelect,
BasicSelectOnPush
],
providers: [
{provide: OverlayContainer, useFactory: () => {
@@ -1255,6 +1263,29 @@ describe('MdSelect', () => {
expect(fixture.componentInstance.changeListener).toHaveBeenCalledTimes(1);
});
});
describe('with OnPush change detection', () => {
let fixture: ComponentFixture<BasicSelectOnPush>;
let trigger: HTMLElement;
beforeEach(() => {
fixture = TestBed.createComponent(BasicSelectOnPush);
fixture.detectChanges();
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
});
it('should update the trigger based on the value', () => {
fixture.componentInstance.control.setValue('pizza-1');
fixture.detectChanges();
expect(trigger.textContent).toContain('Pizza');
fixture.componentInstance.control.reset();
fixture.detectChanges();
expect(trigger.textContent).not.toContain('Pizza');
});
});
});
@Component({
@@ -1433,6 +1464,29 @@ class CompWithCustomSelect {
@ViewChild(CustomSelectAccessor) customAccessor: CustomSelectAccessor;
}
@Component({
selector: 'basic-select-on-push',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<md-select placeholder="Food" [formControl]="control">
<md-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</md-option>
</md-select>
`
})
class BasicSelectOnPush {
foods: any[] = [
{ value: 'steak-0', viewValue: 'Steak' },
{ value: 'pizza-1', viewValue: 'Pizza' },
{ value: 'tacos-2', viewValue: 'Tacos' },
];
control = new FormControl();
@ViewChild(MdSelect) select: MdSelect;
@ViewChildren(MdOption) options: QueryList<MdOption>;
}
/**
* TODO: Move this to core testing utility until Angular has event faking
+4 -2
View File
@@ -13,6 +13,7 @@ import {
Self,
ViewEncapsulation,
ViewChild,
ChangeDetectorRef,
} from '@angular/core';
import {MdOption, MdOptionSelectEvent} from '../core/option/option';
import {ENTER, SPACE} from '../core/keyboard/keycodes';
@@ -233,8 +234,8 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
@Output() change: EventEmitter<MdSelectChange> = new EventEmitter<MdSelectChange>();
constructor(private _element: ElementRef, private _renderer: Renderer,
private _viewportRuler: ViewportRuler, @Optional() private _dir: Dir,
@Self() @Optional() public _control: NgControl) {
private _viewportRuler: ViewportRuler, private _changeDetectorRef: ChangeDetectorRef,
@Optional() private _dir: Dir, @Self() @Optional() public _control: NgControl) {
if (this._control) {
this._control.valueAccessor = this;
}
@@ -301,6 +302,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
}
this._setSelectionByValue(value);
this._changeDetectorRef.markForCheck();
}
/**