Skip to content

Commit 3ca801a

Browse files
amcdnljosephperrott
authored andcommitted
fix: consistently coerce boolean and number properties (#7283)
1 parent 8dc8dc4 commit 3ca801a

File tree

8 files changed

+43
-10
lines changed

8 files changed

+43
-10
lines changed

src/cdk/accordion/accordion-item.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from '@angular/core';
1818
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
1919
import {CdkAccordion} from './accordion';
20+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
2021

2122
/** Used to generate unique ID for each accordion item. */
2223
let nextId = 0;
@@ -41,8 +42,10 @@ export class CdkAccordionItem implements OnDestroy {
4142

4243
/** Whether the AccordionItem is expanded. */
4344
@Input()
44-
get expanded(): boolean { return this._expanded; }
45-
set expanded(expanded: boolean) {
45+
get expanded(): any { return this._expanded; }
46+
set expanded(expanded: any) {
47+
expanded = coerceBooleanProperty(expanded);
48+
4649
// Only emit events and update the internal value if the value changes.
4750
if (this._expanded !== expanded) {
4851
this._expanded = expanded;

src/cdk/coercion/number-property.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
*/
88

99
/** Coerces a data-bound value (typically a string) to a number. */
10+
export function coerceNumberProperty(value: any): number;
11+
export function coerceNumberProperty<D>(value: any, fallback: D): number | D;
1012
export function coerceNumberProperty(value: any, fallbackValue = 0) {
1113
// parseFloat(value) handles most of the cases we're interested in (it treats null, empty string,
1214
// and other non-number values as NaN, where Number just uses 0) but it considers the string

src/lib/datepicker/datepicker.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,22 @@ export class MatDatepicker<D> implements OnDestroy {
145145
* Whether the calendar UI is in touch mode. In touch mode the calendar opens in a dialog rather
146146
* than a popup and elements have more padding to allow for bigger touch targets.
147147
*/
148-
@Input() touchUi = false;
148+
@Input()
149+
get touchUi(): boolean {
150+
return this._touchUi;
151+
}
152+
set touchUi(value: boolean) {
153+
this._touchUi = coerceBooleanProperty(value);
154+
}
155+
private _touchUi = false;
149156

150157
/** Whether the datepicker pop-up should be disabled. */
151158
@Input()
152-
get disabled() {
159+
get disabled(): boolean {
153160
return this._disabled === undefined && this._datepickerInput ?
154161
this._datepickerInput.disabled : !!this._disabled;
155162
}
156-
set disabled(value: any) {
163+
set disabled(value: boolean) {
157164
const newValue = coerceBooleanProperty(value);
158165

159166
if (newValue !== this._disabled) {

src/lib/expansion/expansion-panel.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
2626
import {CanDisable, mixinDisabled} from '@angular/material/core';
2727
import {Subject} from 'rxjs/Subject';
2828
import {MatAccordion} from './accordion';
29+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
2930

3031
/** Workaround for https://github.com/angular/angular/issues/17849 */
3132
export const _CdkAccordionItem = CdkAccordionItem;
@@ -91,8 +92,16 @@ export type MatExpansionPanelState = 'expanded' | 'collapsed';
9192
})
9293
export class MatExpansionPanel extends _MatExpansionPanelMixinBase
9394
implements CanDisable, OnChanges, OnDestroy {
95+
9496
/** Whether the toggle indicator should be hidden. */
95-
@Input() hideToggle: boolean = false;
97+
@Input()
98+
get hideToggle(): boolean {
99+
return this._hideToggle;
100+
}
101+
set hideToggle(value: boolean) {
102+
this._hideToggle = coerceBooleanProperty(value);
103+
}
104+
private _hideToggle = false;
96105

97106
/** Stream that emits for changes in `@Input` properties. */
98107
_inputChanges = new Subject<SimpleChanges>();

src/lib/menu/menu-directive.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {throwMatMenuInvalidPositionX, throwMatMenuInvalidPositionY} from './menu
3939
import {MatMenuItem} from './menu-item';
4040
import {MatMenuPanel} from './menu-panel';
4141
import {MenuPositionX, MenuPositionY} from './menu-positions';
42+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
4243

4344

4445
/** Default `mat-menu` options that can be overridden. */
@@ -122,7 +123,14 @@ export class MatMenu implements AfterContentInit, MatMenuPanel, OnDestroy {
122123
@ContentChildren(MatMenuItem) items: QueryList<MatMenuItem>;
123124

124125
/** Whether the menu should overlap its trigger. */
125-
@Input() overlapTrigger = this._defaultOptions.overlapTrigger;
126+
@Input()
127+
set overlapTrigger(value: boolean) {
128+
this._overlapTrigger = coerceBooleanProperty(value);
129+
}
130+
get overlapTrigger(): boolean {
131+
return this._overlapTrigger;
132+
}
133+
private _overlapTrigger: boolean = this._defaultOptions.overlapTrigger;
126134

127135
/**
128136
* This method takes classes set on the host mat-menu element and applies them on the

src/lib/slide-toggle/slide-toggle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
124124
@Input()
125125
get checked(): boolean { return this._checked; }
126126
set checked(value) {
127-
this._checked = !!value;
127+
this._checked = coerceBooleanProperty(value);
128128
this._changeDetectorRef.markForCheck();
129129
}
130130
/** An event will be dispatched each time the slide-toggle changes its value. */

src/lib/tabs/tab-group.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
ViewChild,
2424
ViewEncapsulation,
2525
} from '@angular/core';
26-
import {coerceBooleanProperty} from '@angular/cdk/coercion';
26+
import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion';
2727
import {Subscription} from 'rxjs/Subscription';
2828
import {MatTab} from './tab';
2929
import {MatTabHeader} from './tab-header';
@@ -109,7 +109,9 @@ export class MatTabGroup extends _MatTabGroupMixinBase implements AfterContentIn
109109

110110
/** The index of the active tab. */
111111
@Input()
112-
set selectedIndex(value: number | null) { this._indexToSelect = value; }
112+
set selectedIndex(value: number | null) {
113+
this._indexToSelect = coerceNumberProperty(value, null);
114+
}
113115
get selectedIndex(): number | null { return this._selectedIndex; }
114116
private _selectedIndex: number | null = null;
115117

src/lib/tabs/tab-header.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {CanDisableRipple, mixinDisableRipple} from '@angular/material/core';
3131
import {merge} from 'rxjs/observable/merge';
3232
import {of as observableOf} from 'rxjs/observable/of';
3333
import {Subscription} from 'rxjs/Subscription';
34+
import {coerceNumberProperty} from '@angular/cdk/coercion';
3435
import {MatInkBar} from './ink-bar';
3536
import {MatTabLabelWrapper} from './tab-label-wrapper';
3637
import {ViewportRuler} from '@angular/cdk/scrolling';
@@ -120,6 +121,7 @@ export class MatTabHeader extends _MatTabHeaderMixinBase
120121
@Input()
121122
get selectedIndex(): number { return this._selectedIndex; }
122123
set selectedIndex(value: number) {
124+
value = coerceNumberProperty(value);
123125
this._selectedIndexChanged = this._selectedIndex != value;
124126
this._selectedIndex = value;
125127
this._focusIndex = value;

0 commit comments

Comments
 (0)