From e07e8e8048c74525f40e2e5a84973520de8a2b54 Mon Sep 17 00:00:00 2001 From: Ed Morales Date: Thu, 6 Jul 2017 15:11:22 -0700 Subject: [PATCH] refactor(disabled): create a disabled mixin to reuse common disabled behavior (#736) * refactor(disabled): create a disabled mixin to reuse common disabled behavior this is the first of many since we need to refactor all common behaviors to centrilize them and make them more reusable. potential mixins could be color, disableRipple, multiple, etc etc) * chore(): polish disabled mixin a bit more make it so its easier to check for boolean changes on its input * *DEPRECATE* feat(chips): rename readOnly to disabled and reuse disabled mixin --- .../components/chips/chips.component.html | 10 ++--- .../components/chips/chips.component.ts | 2 +- src/platform/core/chips/README.md | 7 +-- src/platform/core/chips/chips.component.html | 4 +- .../core/chips/chips.component.spec.ts | 4 +- src/platform/core/chips/chips.component.ts | 44 ++++++++++++------- .../core/common/behaviors/constructor.ts | 1 + .../core/common/behaviors/disabled.mixin.ts | 36 +++++++++++++++ src/platform/core/common/common.module.ts | 6 +++ .../expansion-panel.component.ts | 38 ++++++++-------- .../file/directives/file-drop.directive.ts | 29 ++++++------ .../file/file-input/file-input.component.ts | 35 +++++++-------- .../file/file-upload/file-upload.component.ts | 35 +++++++-------- .../step-header/step-header.component.ts | 16 ++++--- src/platform/core/steps/step.component.ts | 41 ++++++++--------- tslint.json | 2 +- 16 files changed, 181 insertions(+), 129 deletions(-) create mode 100644 src/platform/core/common/behaviors/constructor.ts create mode 100644 src/platform/core/common/behaviors/disabled.mixin.ts diff --git a/src/app/components/components/chips/chips.component.html b/src/app/components/components/chips/chips.component.html index 4aac7c41b4..55399c546e 100644 --- a/src/app/components/components/chips/chips.component.html +++ b/src/app/components/components/chips/chips.component.html @@ -12,7 +12,7 @@ [items]="filteredStrings" [(ngModel)]="stringsModel" placeholder="Enter autocomplete strings" - [readOnly]="readOnly" + [disabled]="disabled" (inputChange)="filterStrings($event)" requireMatch> @@ -29,7 +29,7 @@ [items]="filteredStrings" [(ngModel)]="stringsModel" placeholder="Enter autocomplete strings" - [readOnly]="readOnly" + [disabled]="disabled" (inputChange)="filterStrings($event)" requireMatch> @@ -39,7 +39,7 @@
- - Read only + + Disabled
diff --git a/src/app/components/components/chips/chips.component.ts b/src/app/components/components/chips/chips.component.ts index fe9da73ea2..ef745c79f9 100644 --- a/src/app/components/components/chips/chips.component.ts +++ b/src/app/components/components/chips/chips.component.ts @@ -13,7 +13,7 @@ export class ChipsDemoComponent implements OnInit { @HostBinding('@routeAnimation') routeAnimation: boolean = true; @HostBinding('class.td-route-animation') classAnimation: boolean = true; - readOnly: boolean = false; + disabled: boolean = false; chipAddition: boolean = true; chipRemoval: boolean = true; diff --git a/src/platform/core/chips/README.md b/src/platform/core/chips/README.md index cf054b98a7..7eb30c3cad 100644 --- a/src/platform/core/chips/README.md +++ b/src/platform/core/chips/README.md @@ -17,8 +17,9 @@ Properties: | `requireMatch?` | `boolean` | Blocks custom inputs and only allows selections from the autocomplete list. | `stacked?` | `boolean` | Set stacked or horizontal chips depending on value. Defaults to false. | `placeholder?` | `string` | Placeholder for the autocomplete input. -| `chipAddition` | `boolean` | Disables the ability to add chips. When setting readOnly as true, this will be overriden. Defaults to true. -| `chipRemoval` | `boolean` | Disables the ability to remove chips. When setting readOnly as true, this will be overriden. Defaults to true. +| `disabled?` | `boolean` | Sets disabled state and disabled addition/removal of chips. +| `chipAddition` | `boolean` | Disables the ability to add chips. When setting disabled as true, this will be overriden. Defaults to true. +| `chipRemoval` | `boolean` | Disables the ability to remove chips. When setting disabled as true, this will be overriden. Defaults to true. | `debounce` | `string` | Debounce timeout between keypresses. Defaults to 200. | `add?` | `function` | Method to be executed when a chip is added. Sends chip value as event. | `remove?` | `function` | Method to be executed when a chip is removed. Sends chip value as event. @@ -49,7 +50,7 @@ Example for HTML usage: color="primary" [items]="items" [(ngModel)]="model" - [readOnly]="readOnly" + [disabled]="disabled" [chipAddition]="chipAddition" [chipRemoval]="chipRemoval" (add)="addEvent($event)" diff --git a/src/platform/core/chips/chips.component.html b/src/platform/core/chips/chips.component.html index 0491a87736..beba003a4a 100644 --- a/src/platform/core/chips/chips.component.html +++ b/src/platform/core/chips/chips.component.html @@ -1,6 +1,6 @@
-
+ [class.mat-disabled]="disabled">
diff --git a/src/platform/core/chips/chips.component.spec.ts b/src/platform/core/chips/chips.component.spec.ts index ca6be6759d..a282f141e0 100644 --- a/src/platform/core/chips/chips.component.spec.ts +++ b/src/platform/core/chips/chips.component.spec.ts @@ -471,7 +471,7 @@ describe('Component: Chips', () => { }); - describe('chip removal usage, requires readOnly to be false: ', () => { + describe('chip removal usage, requires disabled to be false: ', () => { let fixture: ComponentFixture; let input: DebugElement; let chips: DebugElement; @@ -668,7 +668,7 @@ describe('Component: Chips', () => { // more a11y unit tests - // readOnly usage + // disabled usage // chipAddition usage diff --git a/src/platform/core/chips/chips.component.ts b/src/platform/core/chips/chips.component.ts index b705e9a3a1..98253b94ea 100644 --- a/src/platform/core/chips/chips.component.ts +++ b/src/platform/core/chips/chips.component.ts @@ -14,6 +14,8 @@ import 'rxjs/add/observable/timer'; import 'rxjs/add/operator/toPromise'; import 'rxjs/add/operator/debounceTime'; +import { ICanDisable, mixinDisabled } from '../common/common.module'; + const noop: any = () => { // empty method }; @@ -36,6 +38,11 @@ export class TdAutocompleteOptionDirective extends TemplatePortalDirective { } } +class TdChipsBase {} + +/* tslint:disable-next-line */ +const _TdChipsMixinBase = mixinDisabled(TdChipsBase); + @Component({ providers: [{ provide: NG_VALUE_ACCESSOR, @@ -43,11 +50,12 @@ export class TdAutocompleteOptionDirective extends TemplatePortalDirective { multi: true, }], selector: 'td-chips', + inputs: ['disabled'], styleUrls: ['./chips.component.scss' ], templateUrl: './chips.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, AfterViewInit, OnDestroy { +export class TdChipsComponent extends _TdChipsMixinBase implements ControlValueAccessor, DoCheck, OnInit, AfterViewInit, OnDestroy, ICanDisable { private _outsideClickSubs: Subscription; @@ -62,7 +70,6 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, private _length: number = 0; private _stacked: boolean = false; private _requireMatch: boolean = false; - private _readOnly: boolean = false; private _color: 'primary' | 'accent' | 'warn' = 'primary'; private _chipAddition: boolean = true; private _chipRemoval: boolean = true; @@ -133,21 +140,18 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, } /** + * @deprecated 1.0.0@beta.6 * readOnly?: boolean * Disables the chips input and chip removal icon. */ @Input('readOnly') set readOnly(readOnly: boolean) { - this._readOnly = readOnly; - this._toggleInput(); - } - get readOnly(): boolean { - return this._readOnly; + this.disabled = readOnly; } /** * chipAddition?: boolean - * Disables the ability to add chips. When setting readOnly as true, this will be overriden. + * Disables the ability to add chips. When setting disabled as true, this will be overriden. * Defaults to true. */ @Input('chipAddition') @@ -160,17 +164,17 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, } /** - * Checks if not in readOnly state and if chipAddition is set to 'true' + * Checks if not in disabled state and if chipAddition is set to 'true' * States if a chip can be added and if the input is available */ get canAddChip(): boolean { - return this.chipAddition && !this.readOnly; + return this.chipAddition && !this.disabled; } /** * chipRemoval?: boolean * Disables the ability to remove chips. If it doesn't exist chip remmoval defaults to true. - * When setting readOnly as true, this will be overriden to false. + * When setting disabled as true, this will be overriden to false. */ @Input('chipRemoval') set chipRemoval(chipRemoval: boolean) { @@ -181,11 +185,11 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, } /** - * Checks if not in readOnly state and if chipRemoval is set to 'true' + * Checks if not in disabled state and if chipRemoval is set to 'true' * States if a chip can be removed */ get canRemoveChip(): boolean { - return this.chipRemoval && !this.readOnly; + return this.chipRemoval && !this.disabled; } /** @@ -255,13 +259,14 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, */ @HostBinding('attr.tabindex') get tabIndex(): number { - return this.readOnly ? -1 : this._tabIndex; + return this.disabled ? -1 : this._tabIndex; } constructor(private _elementRef: ElementRef, private _renderer: Renderer2, private _changeDetectorRef: ChangeDetectorRef, @Optional() @Inject(DOCUMENT) private _document: any) { + super(); this._renderer.addClass(this._elementRef.nativeElement, 'mat-' + this._color); } @@ -359,6 +364,11 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, } } + /** Method executed when the disabled value changes */ + onDisabledChange(v: boolean): void { + this._toggleInput(); + } + /** * Method that is executed when trying to create a new chip from the autocomplete. * It check if [requireMatch] is enabled, and tries to add the first active option @@ -462,7 +472,7 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, * Sets focus state of the component */ setFocusedState(): void { - if (!this.readOnly) { + if (!this.disabled) { this._focused = true; this._tabIndex = -1; this._changeDetectorRef.markForCheck(); @@ -485,7 +495,7 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, focus(): void { if (this.canAddChip) { this._inputChild.focus(); - } else if (!this.readOnly) { + } else if (!this.disabled) { this._focusFirstChip(); } } @@ -664,7 +674,7 @@ export class TdChipsComponent implements ControlValueAccessor, DoCheck, OnInit, /** * Method to toggle the disable state of input - * Checks if not in readOnly state and if chipAddition is set to 'true' + * Checks if not in disabled state and if chipAddition is set to 'true' */ private _toggleInput(): void { if (this.canAddChip) { diff --git a/src/platform/core/common/behaviors/constructor.ts b/src/platform/core/common/behaviors/constructor.ts new file mode 100644 index 0000000000..f758baa2e9 --- /dev/null +++ b/src/platform/core/common/behaviors/constructor.ts @@ -0,0 +1 @@ +export type Constructor = new (...args: any[]) => T; diff --git a/src/platform/core/common/behaviors/disabled.mixin.ts b/src/platform/core/common/behaviors/disabled.mixin.ts new file mode 100644 index 0000000000..dc8a69c191 --- /dev/null +++ b/src/platform/core/common/behaviors/disabled.mixin.ts @@ -0,0 +1,36 @@ +import { Constructor } from './constructor'; + +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; + +/** Interface to implement when applying the disabled mixin */ +export interface ICanDisable { + disabled: boolean; + onDisabledChange(v: boolean): void; +} + +/** Mixin to augment a component or directive with a `disabled` property. */ +export function mixinDisabled>(base: T): Constructor & T { + return class extends base { + private _disabled: boolean = false; + + constructor(...args: any[]) { + super(...args); + } + + get disabled(): boolean { + return this._disabled; + } + set disabled(value: boolean) { + let newValue: boolean = value !== '' ? (value === 'true' || value === true) : true; + if (this._disabled !== newValue) { + this._disabled = newValue; + this.onDisabledChange(this._disabled); + } + } + + onDisabledChange(v: boolean): void { + /** NOT IMPLEMENTED, this needs to be overriden by subclasses if needed */ + } + }; +} diff --git a/src/platform/core/common/common.module.ts b/src/platform/core/common/common.module.ts index 2936622908..d5435dd408 100644 --- a/src/platform/core/common/common.module.ts +++ b/src/platform/core/common/common.module.ts @@ -20,6 +20,12 @@ export { TdToggleDirective, TdFadeDirective }; export { TdCollapseAnimation } from './animations/collapse/collapse.animation'; export { TdFadeInOutAnimation } from './animations/fade/fadeInOut.animation'; +/** + * BEHAVIORS + */ + +export { ICanDisable, mixinDisabled } from './behaviors/disabled.mixin'; + /** * FORMS */ diff --git a/src/platform/core/expansion-panel/expansion-panel.component.ts b/src/platform/core/expansion-panel/expansion-panel.component.ts index ef91ea6c18..aafe847245 100644 --- a/src/platform/core/expansion-panel/expansion-panel.component.ts +++ b/src/platform/core/expansion-panel/expansion-panel.component.ts @@ -3,7 +3,7 @@ import { Component, Directive, Input, Output, TemplateRef, ViewContainerRef, Con import { EventEmitter } from '@angular/core'; import { TemplatePortalDirective } from '@angular/material'; -import { TdCollapseAnimation } from '../common/common.module'; +import { TdCollapseAnimation, ICanDisable, mixinDisabled } from '../common/common.module'; @Directive({ selector: '[td-expansion-panel-header]ng-template', @@ -38,19 +38,24 @@ export class TdExpansionPanelSublabelDirective extends TemplatePortalDirective { }) export class TdExpansionPanelSummaryComponent {} +class TdExpansionPanelBase {} + +/* tslint:disable-next-line */ +const _TdExpansionPanelMixinBase = mixinDisabled(TdExpansionPanelBase); + @Component({ selector: 'td-expansion-panel', styleUrls: ['./expansion-panel.component.scss' ], templateUrl: './expansion-panel.component.html', + inputs: ['disabled'], animations: [ TdCollapseAnimation(), ], }) -export class TdExpansionPanelComponent { +export class TdExpansionPanelComponent extends _TdExpansionPanelMixinBase implements ICanDisable { private _disableRipple: boolean = false; private _expand: boolean = false; - private _disabled: boolean = false; @ContentChild(TdExpansionPanelHeaderDirective) expansionPanelHeader: TdExpansionPanelHeaderDirective; @ContentChild(TdExpansionPanelLabelDirective) expansionPanelLabel: TdExpansionPanelLabelDirective; @@ -93,22 +98,6 @@ export class TdExpansionPanelComponent { return this._expand; } - /** - * disabled?: boolean - * Disables icon and header, blocks click event and sets [TdStepComponent] to deactive if 'true'. - */ - @Input('disabled') - set disabled(disabled: boolean) { - if (disabled && this._expand) { - this._expand = false; - this._onCollapsed(); - } - this._disabled = disabled; - } - get disabled(): boolean { - return this._disabled; - } - /** * expanded?: function * Event emitted when [TdExpansionPanelComponent] is expanded. @@ -123,6 +112,7 @@ export class TdExpansionPanelComponent { constructor(private _renderer: Renderer2, private _elementRef: ElementRef) { + super(); this._renderer.addClass(this._elementRef.nativeElement, 'td-expansion-panel'); } @@ -157,12 +147,20 @@ export class TdExpansionPanelComponent { return this._setExpand(false); } + /** Method executed when the disabled value changes */ + onDisabledChange(v: boolean): void { + if (v && this._expand) { + this._expand = false; + this._onCollapsed(); + } + } + /** * Method to change expand state internally and emit the [onExpanded] event if 'true' or [onCollapsed] * event if 'false'. (Blocked if [disabled] is 'true') */ private _setExpand(newExpand: boolean): boolean { - if (this._disabled) { + if (this.disabled) { return false; } if (this._expand !== newExpand) { diff --git a/src/platform/core/file/directives/file-drop.directive.ts b/src/platform/core/file/directives/file-drop.directive.ts index 51e4638042..06c890ab5e 100644 --- a/src/platform/core/file/directives/file-drop.directive.ts +++ b/src/platform/core/file/directives/file-drop.directive.ts @@ -1,13 +1,20 @@ import { Directive, Input, Output, EventEmitter } from '@angular/core'; import { HostListener, HostBinding, ElementRef, Renderer2 } from '@angular/core'; +import { ICanDisable, mixinDisabled } from '../../common/common.module'; + +class TdFileDropBase {} + +/* tslint:disable-next-line */ +const _TdFileDropMixinBase = mixinDisabled(TdFileDropBase); + @Directive({ selector: '[tdFileDrop]', + inputs: ['disabled'], }) -export class TdFileDropDirective { +export class TdFileDropDirective extends _TdFileDropMixinBase implements ICanDisable { private _multiple: boolean = false; - private _disabled: boolean = false; /** * multiple?: boolean @@ -19,15 +26,6 @@ export class TdFileDropDirective { this._multiple = multiple !== '' ? (multiple === 'true' || multiple === true) : true; } - /** - * disabled?: boolean - * Disabled drop events for host element. - */ - @Input('disabled') - set disabled(disabled: boolean) { - this._disabled = disabled; - } - /** * fileDrop?: function * Event emitted when a file or files are dropped in host element after being validated. @@ -48,10 +46,11 @@ export class TdFileDropDirective { */ @HostBinding('attr.disabled') get disabledBinding(): string { - return this._disabled ? '' : undefined; + return this.disabled ? '' : undefined; } constructor(private _renderer: Renderer2, private _element: ElementRef) { + super(); } /** @@ -61,7 +60,7 @@ export class TdFileDropDirective { */ @HostListener('drop', ['$event']) onDrop(event: Event): void { - if (!this._disabled) { + if (!this.disabled) { let transfer: DataTransfer = (event).dataTransfer; let files: FileList = transfer.files; if (files.length) { @@ -82,7 +81,7 @@ export class TdFileDropDirective { onDragOver(event: Event): void { let transfer: DataTransfer = (event).dataTransfer; transfer.dropEffect = this._typeCheck(transfer.types); - if (this._disabled || (!this._multiple && + if (this.disabled || (!this._multiple && ((transfer.items && transfer.items.length > 1) || (transfer).mozItemCount > 1))) { transfer.dropEffect = 'none'; } else { @@ -97,7 +96,7 @@ export class TdFileDropDirective { */ @HostListener('dragenter', ['$event']) onDragEnter(event: Event): void { - if (!this._disabled) { + if (!this.disabled) { this._renderer.addClass(this._element.nativeElement, 'drop-zone'); } this._stopEvent(event); diff --git a/src/platform/core/file/file-input/file-input.component.ts b/src/platform/core/file/file-input/file-input.component.ts index e23ae01baa..cb0762eb63 100644 --- a/src/platform/core/file/file-input/file-input.component.ts +++ b/src/platform/core/file/file-input/file-input.component.ts @@ -3,6 +3,8 @@ import { Component, Directive, Input, Output, EventEmitter, ChangeDetectionStrat import { TemplatePortalDirective } from '@angular/material'; import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; +import { ICanDisable, mixinDisabled } from '../../common/common.module'; + const noop: any = () => { // empty method }; @@ -22,14 +24,20 @@ export class TdFileInputLabelDirective extends TemplatePortalDirective { } } +class TdFileInputBase {} + +/* tslint:disable-next-line */ +const _TdFileInputMixinBase = mixinDisabled(TdFileInputBase); + @Component({ changeDetection: ChangeDetectionStrategy.OnPush, providers: [ FILE_INPUT_CONTROL_VALUE_ACCESSOR ], selector: 'td-file-input', + inputs: ['disabled'], styleUrls: ['./file-input.component.scss'], templateUrl: './file-input.component.html', }) -export class TdFileInputComponent implements ControlValueAccessor { +export class TdFileInputComponent extends _TdFileInputMixinBase implements ControlValueAccessor, ICanDisable { /** * Implemented as part of ControlValueAccessor. @@ -46,7 +54,6 @@ export class TdFileInputComponent implements ControlValueAccessor { } private _multiple: boolean = false; - private _disabled: boolean = false; /** The native ` element */ @ViewChild('fileInput') _inputElement: ElementRef; @@ -79,21 +86,6 @@ export class TdFileInputComponent implements ControlValueAccessor { */ @Input('accept') accept: string; - /** - * disabled?: boolean - * Disables [TdFileInputComponent] and clears selected/dropped files. - */ - @Input('disabled') - set disabled(disabled: boolean) { - if (disabled) { - this.clear(); - } - this._disabled = disabled; - } - get disabled(): boolean { - return this._disabled; - } - /** * select?: function * Event emitted a file is selected @@ -102,7 +94,7 @@ export class TdFileInputComponent implements ControlValueAccessor { @Output('select') onSelect: EventEmitter = new EventEmitter(); constructor(private _renderer: Renderer2, private _changeDetectorRef: ChangeDetectorRef) { - + super(); } /** @@ -121,6 +113,13 @@ export class TdFileInputComponent implements ControlValueAccessor { this._renderer.setProperty(this.inputElement, 'value', ''); } + /** Method executed when the disabled value changes */ + onDisabledChange(v: boolean): void { + if (v) { + this.clear(); + } + } + /** * Implemented as part of ControlValueAccessor. */ diff --git a/src/platform/core/file/file-upload/file-upload.component.ts b/src/platform/core/file/file-upload/file-upload.component.ts index 66adffc6ca..86645abf1c 100644 --- a/src/platform/core/file/file-upload/file-upload.component.ts +++ b/src/platform/core/file/file-upload/file-upload.component.ts @@ -1,17 +1,24 @@ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ContentChild, ChangeDetectorRef } from '@angular/core'; +import { ICanDisable, mixinDisabled } from '../../common/common.module'; + import { TdFileInputComponent, TdFileInputLabelDirective } from '../file-input/file-input.component'; +class TdFileUploadBase {} + +/* tslint:disable-next-line */ +const _TdFileUploadMixinBase = mixinDisabled(TdFileUploadBase); + @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'td-file-upload', + inputs: ['disabled'], styleUrls: ['./file-upload.component.scss'], templateUrl: './file-upload.component.html', }) -export class TdFileUploadComponent { +export class TdFileUploadComponent extends _TdFileUploadMixinBase implements ICanDisable { private _multiple: boolean = false; - private _disabled: boolean = false; files: FileList | File; @@ -54,21 +61,6 @@ export class TdFileUploadComponent { */ @Input('accept') accept: string; - /** - * disabled?: boolean - * Disables [TdFileUploadComponent] and clears selected/dropped files. - */ - @Input('disabled') - set disabled(disabled: boolean) { - if (disabled) { - this.cancel(); - } - this._disabled = disabled; - } - get disabled(): boolean { - return this._disabled; - } - /** * select?: function * Event emitted when a file is selecte. @@ -90,7 +82,7 @@ export class TdFileUploadComponent { @Output('cancel') onCancel: EventEmitter = new EventEmitter(); constructor(private _changeDetectorRef: ChangeDetectorRef) { - + super(); } /** @@ -120,4 +112,11 @@ export class TdFileUploadComponent { this.onCancel.emit(undefined); this._changeDetectorRef.markForCheck(); } + + /** Method executed when the disabled value changes */ + onDisabledChange(v: boolean): void { + if (v) { + this.cancel(); + } + } } diff --git a/src/platform/core/steps/step-header/step-header.component.ts b/src/platform/core/steps/step-header/step-header.component.ts index 2f934ebee1..8534a07945 100644 --- a/src/platform/core/steps/step-header/step-header.component.ts +++ b/src/platform/core/steps/step-header/step-header.component.ts @@ -1,13 +1,21 @@ import { Component, Input } from '@angular/core'; +import { ICanDisable, mixinDisabled } from '../../common/common.module'; + import { StepState } from '../step.component'; +class TdStepHeaderBase {} + +/* tslint:disable-next-line */ +const _TdStepHeaderMixinBase = mixinDisabled(TdStepHeaderBase); + @Component({ selector: 'td-step-header', + inputs: ['disabled'], styleUrls: ['./step-header.component.scss' ], templateUrl: './step-header.component.html', }) -export class TdStepHeaderComponent { +export class TdStepHeaderComponent extends _TdStepHeaderMixinBase implements ICanDisable { /** * Number assigned to [TdStepHeaderComponent]. @@ -26,12 +34,6 @@ export class TdStepHeaderComponent { */ @Input('active') active: boolean; - /** - * disabled?: boolean - * Sets styles for disabled state on icon and header. - */ - @Input('disabled') disabled: boolean; - /** * state?: StepState or ['none' | 'required' | 'complete'] * Sets styles for state of header. diff --git a/src/platform/core/steps/step.component.ts b/src/platform/core/steps/step.component.ts index 13929a5ba0..f9f5bcdbc1 100644 --- a/src/platform/core/steps/step.component.ts +++ b/src/platform/core/steps/step.component.ts @@ -3,6 +3,8 @@ import { Component, Directive, Input, Output, TemplateRef, ViewChild, import { EventEmitter } from '@angular/core'; import { TemplatePortalDirective, TemplatePortal } from '@angular/material'; +import { ICanDisable, mixinDisabled } from '../common/common.module'; + export enum StepState { None = 'none', Required = 'required', @@ -36,16 +38,21 @@ export class TdStepSummaryDirective extends TemplatePortalDirective { } } +class TdStepBase {} + +/* tslint:disable-next-line */ +const _TdStepMixinBase = mixinDisabled(TdStepBase); + @Component({ selector: 'td-step', + inputs: ['disabled'], templateUrl: './step.component.html', }) -export class TdStepComponent implements OnInit { +export class TdStepComponent extends _TdStepMixinBase implements OnInit, ICanDisable { private _disableRipple: boolean = false; private _active: boolean = false; private _state: StepState = StepState.None; - private _disabled: boolean = false; private _contentPortal: TemplatePortal; get stepContent(): TemplatePortal { @@ -94,22 +101,6 @@ export class TdStepComponent implements OnInit { return this._active; } - /** - * disabled?: boolean - * Disables icon and header, blocks click event and sets [TdStepComponent] to deactive if 'true'. - */ - @Input('disabled') - set disabled(disabled: boolean) { - if (disabled && this._active) { - this._active = false; - this._onDeactivated(); - } - this._disabled = disabled; - } - get disabled(): boolean { - return this._disabled; - } - /** * state?: StepState or ['none' | 'required' | 'complete'] * Sets state of [TdStepComponent] depending on value. @@ -145,7 +136,9 @@ export class TdStepComponent implements OnInit { */ @Output('deactivated') onDeactivated: EventEmitter = new EventEmitter(); - constructor(private _viewContainerRef: ViewContainerRef) {} + constructor(private _viewContainerRef: ViewContainerRef) { + super(); + } ngOnInit(): void { this._contentPortal = new TemplatePortal(this._content, this._viewContainerRef); @@ -182,13 +175,21 @@ export class TdStepComponent implements OnInit { return this._state === StepState.Complete; } + /** Method executed when the disabled value changes */ + onDisabledChange(v: boolean): void { + if (v && this._active) { + this._active = false; + this._onDeactivated(); + } + } + /** * Method to change active state internally and emit the [onActivated] event if 'true' or [onDeactivated] * event if 'false'. (Blocked if [disabled] is 'true') * returns true if successfully changed state */ private _setActive(newActive: boolean): boolean { - if (this._disabled) { + if (this.disabled) { return false; } if (this._active !== newActive) { diff --git a/tslint.json b/tslint.json index c2992fee30..7ad3e9e18e 100644 --- a/tslint.json +++ b/tslint.json @@ -188,7 +188,7 @@ "component-selector": [false, "element", "td", "kebab-case"], "component-class-suffix": true, "directive-class-suffix": false, // Checked in PR's (different suffix for validators and so) - "use-input-property-decorator": true, + "use-input-property-decorator": false, // Checked in PR's (mixins need a diff approach) "use-output-property-decorator": true, "use-host-property-decorator": true, "no-attribute-parameter-decorator": true,