Skip to content

Commit

Permalink
fix: consistently coerce boolean and number properties (#7283)
Browse files Browse the repository at this point in the history
  • Loading branch information
amcdnl authored and josephperrott committed Nov 10, 2017
1 parent 8dc8dc4 commit 3ca801a
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 10 deletions.
7 changes: 5 additions & 2 deletions src/cdk/accordion/accordion-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '@angular/core';
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
import {CdkAccordion} from './accordion';
import {coerceBooleanProperty} from '@angular/cdk/coercion';

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

/** Whether the AccordionItem is expanded. */
@Input()
get expanded(): boolean { return this._expanded; }
set expanded(expanded: boolean) {
get expanded(): any { return this._expanded; }
set expanded(expanded: any) {
expanded = coerceBooleanProperty(expanded);

// Only emit events and update the internal value if the value changes.
if (this._expanded !== expanded) {
this._expanded = expanded;
Expand Down
2 changes: 2 additions & 0 deletions src/cdk/coercion/number-property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/

/** Coerces a data-bound value (typically a string) to a number. */
export function coerceNumberProperty(value: any): number;
export function coerceNumberProperty<D>(value: any, fallback: D): number | D;
export function coerceNumberProperty(value: any, fallbackValue = 0) {
// parseFloat(value) handles most of the cases we're interested in (it treats null, empty string,
// and other non-number values as NaN, where Number just uses 0) but it considers the string
Expand Down
13 changes: 10 additions & 3 deletions src/lib/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,22 @@ export class MatDatepicker<D> implements OnDestroy {
* Whether the calendar UI is in touch mode. In touch mode the calendar opens in a dialog rather
* than a popup and elements have more padding to allow for bigger touch targets.
*/
@Input() touchUi = false;
@Input()
get touchUi(): boolean {
return this._touchUi;
}
set touchUi(value: boolean) {
this._touchUi = coerceBooleanProperty(value);
}
private _touchUi = false;

/** Whether the datepicker pop-up should be disabled. */
@Input()
get disabled() {
get disabled(): boolean {
return this._disabled === undefined && this._datepickerInput ?
this._datepickerInput.disabled : !!this._disabled;
}
set disabled(value: any) {
set disabled(value: boolean) {
const newValue = coerceBooleanProperty(value);

if (newValue !== this._disabled) {
Expand Down
11 changes: 10 additions & 1 deletion src/lib/expansion/expansion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
import {CanDisable, mixinDisabled} from '@angular/material/core';
import {Subject} from 'rxjs/Subject';
import {MatAccordion} from './accordion';
import {coerceBooleanProperty} from '@angular/cdk/coercion';

/** Workaround for https://github.com/angular/angular/issues/17849 */
export const _CdkAccordionItem = CdkAccordionItem;
Expand Down Expand Up @@ -91,8 +92,16 @@ export type MatExpansionPanelState = 'expanded' | 'collapsed';
})
export class MatExpansionPanel extends _MatExpansionPanelMixinBase
implements CanDisable, OnChanges, OnDestroy {

/** Whether the toggle indicator should be hidden. */
@Input() hideToggle: boolean = false;
@Input()
get hideToggle(): boolean {
return this._hideToggle;
}
set hideToggle(value: boolean) {
this._hideToggle = coerceBooleanProperty(value);
}
private _hideToggle = false;

/** Stream that emits for changes in `@Input` properties. */
_inputChanges = new Subject<SimpleChanges>();
Expand Down
10 changes: 9 additions & 1 deletion src/lib/menu/menu-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {throwMatMenuInvalidPositionX, throwMatMenuInvalidPositionY} from './menu
import {MatMenuItem} from './menu-item';
import {MatMenuPanel} from './menu-panel';
import {MenuPositionX, MenuPositionY} from './menu-positions';
import {coerceBooleanProperty} from '@angular/cdk/coercion';


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

/** Whether the menu should overlap its trigger. */
@Input() overlapTrigger = this._defaultOptions.overlapTrigger;
@Input()
set overlapTrigger(value: boolean) {
this._overlapTrigger = coerceBooleanProperty(value);
}
get overlapTrigger(): boolean {
return this._overlapTrigger;
}
private _overlapTrigger: boolean = this._defaultOptions.overlapTrigger;

/**
* This method takes classes set on the host mat-menu element and applies them on the
Expand Down
2 changes: 1 addition & 1 deletion src/lib/slide-toggle/slide-toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class MatSlideToggle extends _MatSlideToggleMixinBase implements OnDestro
@Input()
get checked(): boolean { return this._checked; }
set checked(value) {
this._checked = !!value;
this._checked = coerceBooleanProperty(value);
this._changeDetectorRef.markForCheck();
}
/** An event will be dispatched each time the slide-toggle changes its value. */
Expand Down
6 changes: 4 additions & 2 deletions src/lib/tabs/tab-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
ViewChild,
ViewEncapsulation,
} from '@angular/core';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {coerceBooleanProperty, coerceNumberProperty} from '@angular/cdk/coercion';
import {Subscription} from 'rxjs/Subscription';
import {MatTab} from './tab';
import {MatTabHeader} from './tab-header';
Expand Down Expand Up @@ -109,7 +109,9 @@ export class MatTabGroup extends _MatTabGroupMixinBase implements AfterContentIn

/** The index of the active tab. */
@Input()
set selectedIndex(value: number | null) { this._indexToSelect = value; }
set selectedIndex(value: number | null) {
this._indexToSelect = coerceNumberProperty(value, null);
}
get selectedIndex(): number | null { return this._selectedIndex; }
private _selectedIndex: number | null = null;

Expand Down
2 changes: 2 additions & 0 deletions src/lib/tabs/tab-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {CanDisableRipple, mixinDisableRipple} from '@angular/material/core';
import {merge} from 'rxjs/observable/merge';
import {of as observableOf} from 'rxjs/observable/of';
import {Subscription} from 'rxjs/Subscription';
import {coerceNumberProperty} from '@angular/cdk/coercion';
import {MatInkBar} from './ink-bar';
import {MatTabLabelWrapper} from './tab-label-wrapper';
import {ViewportRuler} from '@angular/cdk/scrolling';
Expand Down Expand Up @@ -120,6 +121,7 @@ export class MatTabHeader extends _MatTabHeaderMixinBase
@Input()
get selectedIndex(): number { return this._selectedIndex; }
set selectedIndex(value: number) {
value = coerceNumberProperty(value);
this._selectedIndexChanged = this._selectedIndex != value;
this._selectedIndex = value;
this._focusIndex = value;
Expand Down

0 comments on commit 3ca801a

Please sign in to comment.