From 3bcb7c3314732b2aa690990c7c117e0c89d9bd47 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 9 Feb 2017 19:31:55 +0100 Subject: [PATCH] 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. --- src/lib/select/select.spec.ts | 58 +++++++++++++++++++++++++++++++++-- src/lib/select/select.ts | 6 ++-- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts index b5bbf8be0c16..215b99a03401 100644 --- a/src/lib/select/select.spec.ts +++ b/src/lib/select/select.spec.ts @@ -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; + 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: ` + + + {{ food.viewValue }} + + + ` +}) +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; +} + /** * TODO: Move this to core testing utility until Angular has event faking diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index e8acad581c72..259057a20a67 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -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 = new EventEmitter(); 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(); } /**