Skip to content

Commit

Permalink
fix(select): view not updating when using OnPush detection strategy (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
crisbeto authored and tinayuangao committed Feb 9, 2017
1 parent 1a89a08 commit 3bcb7c3
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 4 deletions.
58 changes: 56 additions & 2 deletions src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -26,7 +33,8 @@ describe('MdSelect', () => {
SelectInitWithoutOptions,
SelectWithChangeEvent,
CustomSelectAccessor,
CompWithCustomSelect
CompWithCustomSelect,
BasicSelectOnPush
],
providers: [
{provide: OverlayContainer, useFactory: () => {
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -301,6 +302,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
}

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

/**
Expand Down

0 comments on commit 3bcb7c3

Please sign in to comment.