Skip to content

Commit 3bcb7c3

Browse files
crisbetotinayuangao
authored andcommitted
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.
1 parent 1a89a08 commit 3bcb7c3

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

src/lib/select/select.spec.ts

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import {TestBed, async, ComponentFixture, fakeAsync, tick} from '@angular/core/testing';
22
import {By} from '@angular/platform-browser';
3-
import {Component, DebugElement, QueryList, ViewChild, ViewChildren} from '@angular/core';
3+
import {
4+
Component,
5+
DebugElement,
6+
QueryList,
7+
ViewChild,
8+
ViewChildren,
9+
ChangeDetectionStrategy,
10+
} from '@angular/core';
411
import {MdSelectModule} from './index';
512
import {OverlayContainer} from '../core/overlay/overlay-container';
613
import {MdSelect} from './select';
@@ -26,7 +33,8 @@ describe('MdSelect', () => {
2633
SelectInitWithoutOptions,
2734
SelectWithChangeEvent,
2835
CustomSelectAccessor,
29-
CompWithCustomSelect
36+
CompWithCustomSelect,
37+
BasicSelectOnPush
3038
],
3139
providers: [
3240
{provide: OverlayContainer, useFactory: () => {
@@ -1255,6 +1263,29 @@ describe('MdSelect', () => {
12551263
expect(fixture.componentInstance.changeListener).toHaveBeenCalledTimes(1);
12561264
});
12571265
});
1266+
1267+
describe('with OnPush change detection', () => {
1268+
let fixture: ComponentFixture<BasicSelectOnPush>;
1269+
let trigger: HTMLElement;
1270+
1271+
beforeEach(() => {
1272+
fixture = TestBed.createComponent(BasicSelectOnPush);
1273+
fixture.detectChanges();
1274+
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
1275+
});
1276+
1277+
it('should update the trigger based on the value', () => {
1278+
fixture.componentInstance.control.setValue('pizza-1');
1279+
fixture.detectChanges();
1280+
1281+
expect(trigger.textContent).toContain('Pizza');
1282+
1283+
fixture.componentInstance.control.reset();
1284+
fixture.detectChanges();
1285+
1286+
expect(trigger.textContent).not.toContain('Pizza');
1287+
});
1288+
});
12581289
});
12591290

12601291
@Component({
@@ -1433,6 +1464,29 @@ class CompWithCustomSelect {
14331464
@ViewChild(CustomSelectAccessor) customAccessor: CustomSelectAccessor;
14341465
}
14351466

1467+
@Component({
1468+
selector: 'basic-select-on-push',
1469+
changeDetection: ChangeDetectionStrategy.OnPush,
1470+
template: `
1471+
<md-select placeholder="Food" [formControl]="control">
1472+
<md-option *ngFor="let food of foods" [value]="food.value">
1473+
{{ food.viewValue }}
1474+
</md-option>
1475+
</md-select>
1476+
`
1477+
})
1478+
class BasicSelectOnPush {
1479+
foods: any[] = [
1480+
{ value: 'steak-0', viewValue: 'Steak' },
1481+
{ value: 'pizza-1', viewValue: 'Pizza' },
1482+
{ value: 'tacos-2', viewValue: 'Tacos' },
1483+
];
1484+
control = new FormControl();
1485+
1486+
@ViewChild(MdSelect) select: MdSelect;
1487+
@ViewChildren(MdOption) options: QueryList<MdOption>;
1488+
}
1489+
14361490

14371491
/**
14381492
* TODO: Move this to core testing utility until Angular has event faking

src/lib/select/select.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Self,
1414
ViewEncapsulation,
1515
ViewChild,
16+
ChangeDetectorRef,
1617
} from '@angular/core';
1718
import {MdOption, MdOptionSelectEvent} from '../core/option/option';
1819
import {ENTER, SPACE} from '../core/keyboard/keycodes';
@@ -233,8 +234,8 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
233234
@Output() change: EventEmitter<MdSelectChange> = new EventEmitter<MdSelectChange>();
234235

235236
constructor(private _element: ElementRef, private _renderer: Renderer,
236-
private _viewportRuler: ViewportRuler, @Optional() private _dir: Dir,
237-
@Self() @Optional() public _control: NgControl) {
237+
private _viewportRuler: ViewportRuler, private _changeDetectorRef: ChangeDetectorRef,
238+
@Optional() private _dir: Dir, @Self() @Optional() public _control: NgControl) {
238239
if (this._control) {
239240
this._control.valueAccessor = this;
240241
}
@@ -301,6 +302,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
301302
}
302303

303304
this._setSelectionByValue(value);
305+
this._changeDetectorRef.markForCheck();
304306
}
305307

306308
/**

0 commit comments

Comments
 (0)