Skip to content

Commit

Permalink
feature(validators): min/max/number-required directives (#98)
Browse files Browse the repository at this point in the history
* added min/max/number-required validators

* update(docs): add min/max directive docs

* update(docs): add tdFade to directives

* update(fade): ts example
  • Loading branch information
emoralesb05 authored and kyleledbetter committed Oct 12, 2016
1 parent 01cbd92 commit 7b7b676
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 3 deletions.
68 changes: 66 additions & 2 deletions src/app/components/components/directives/directives.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
<p>Click on this to open a div:</p>
<button md-raised-button color="accent" (click)="toggle()">Toggle</button>
<div [tdToggle]="toggleDiv" [hidden]>
Reveal or hide with a toggle click!
<md-card>
<md-card-title>Toggle Card</md-card-title>
<md-card-content>Reveal or hide with a toggle click!</md-card-content>
<md-card-actions><button md-raised-button color="primary" (click)="toggle()">Toggle Out</button></md-card-actions>
</md-card>
</div>
<p>HTML:</p>
<td-highlight lang="html">
Expand All @@ -61,4 +65,64 @@
{{ '}' }}
</td-highlight>
</md-card-content>
</md-card>
</md-card>

<md-card>
<md-card-title>Fade directive</md-card-title>
<md-divider></md-divider>
<md-card-content>
<p class="md-body-1">Use <code>[tdFade]="variable"</code> on an element to fade it in and out.</p>
<p>Click on this to open a div:</p>
<button md-raised-button color="accent" (click)="fade()">Fade</button>
<div [tdFade]="fadeDiv" [hidden]>
<md-card>
<md-card-title>Fade Card</md-card-title>
<md-card-content>Fade in or out with a click!</md-card-content>
<md-card-actions><button md-raised-button color="primary" (click)="fade()">Fade Out</button></md-card-actions>
</md-card>
</div>
<p>HTML:</p>
<td-highlight lang="html">
<![CDATA[
<button md-raised-button color="accent" (click)="fade()">Toggle</button>
<div [tdFade]="fadeDiv" [hidden]>
This one fades in and out!
</div>
]]>
</td-highlight>
<p>TypeScript:</p>
<td-highlight lang="typescript">
fadeDiv: boolean = true;

fade(): any {{ '{' }}
this.fadeDiv = !this.fadeDiv;
{{ '}' }}
</td-highlight>
</md-card-content>
</md-card>

<md-card>
<md-card-title>Min/Max/Number Validators</md-card-title>
<md-divider></md-divider>
<md-card-content>
<p class="md-body-1">We've added min/max/number-required validations since ng2 doesnt support them at the moment.</p>
<p>Supported:</p>
<ul>
<li><code>TdMinValidator</code> for selector: <code>[min][formControlName]</code>,<code>[min][formControl]</code>,<code>[min][ngModel]</code></li>
<li><code>TdMaxValidator</code> for selector: <code>[max][formControlName]</code>,<code>[max][formControl]</code>,<code>[max][ngModel]</code></li>
<li><code>TdNumberRequiredValidator</code> for selector: <code>[type=number][required][formControlName]</code>,<code>[type=number][required][formControl]</code>,<code>[type=number][required][ngModel]</code></li>
</ul>
<p>Example enter lower than 5 or higher than 10:</p>
<div layout="row">
<md-input flex="20" placeholder="CPUs" #el="ngModel" type="number" [(ngModel)]="val" min="5" max="10" required></md-input>
</div>
<p>Errors:</p>
<code>{{el?.errors | json}}</code>
<p>HTML:</p>
<td-highlight lang="html">
<![CDATA[
<md-input placeholder="CPUs" #el="ngModel" type="number" [(ngModel)]="val" min="5" max="10" required></md-input>
]]>
</td-highlight>
</md-card-content>
</md-card>
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ import { Component } from '@angular/core';
export class DirectivesComponent {

toggleDiv: boolean = true;
fadeDiv: boolean = true;

toggle(): void {
this.toggleDiv = !this.toggleDiv;
}
fade(): void {
this.fadeDiv = !this.fadeDiv;
}
}
19 changes: 19 additions & 0 deletions src/platform/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,23 @@ export { TdToggleDirective } from './directives/toggle/toggle.directive';
export { TdFadeDirective } from './directives/fade/fade.directive';
export { TdAutoTrimDirective } from './directives/auto-trim/auto-trim.directive';

/**
* VALIDATORS
*/
import { TdMinValidator } from './validators/min.validator';
import { TdMaxValidator } from './validators/max.validator';
import { TdNumberRequiredValidator } from './validators/number-required.validator';

export const TD_VALIDATORS: Type<any>[] = [
TdMinValidator,
TdMaxValidator,
TdNumberRequiredValidator,
];

export { TdMinValidator } from './validators/min.validator';
export { TdMaxValidator } from './validators/max.validator';
export { TdNumberRequiredValidator } from './validators/number-required.validator';

/**
* PIPES
*/
Expand Down Expand Up @@ -182,6 +199,7 @@ export { TdMediaToggleDirective } from './media/directives/media-toggle.directiv
TD_EXPANSION_DIRECTIVES,
TD_DIALOG_DIRECTIVES,
TD_PLATFORM_DIRECTIVES,
TD_VALIDATORS,
],
exports: [
HttpModule,
Expand All @@ -199,6 +217,7 @@ export { TdMediaToggleDirective } from './media/directives/media-toggle.directiv
TD_EXPANSION_DIRECTIVES,
TD_DIALOG_DIRECTIVES,
TD_PLATFORM_DIRECTIVES,
TD_VALIDATORS,
],
entryComponents: [ TD_DIALOG_ENTRY_COMPONENTS ],
})
Expand Down
40 changes: 40 additions & 0 deletions src/platform/core/validators/max.validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Directive, Input, forwardRef } from '@angular/core';
import { NG_VALIDATORS, Validator, Validators, AbstractControl, ValidatorFn } from '@angular/forms';

import { TdNumberRequiredValidator } from './number-required.validator';

export const MAX_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => TdMaxValidator),
multi: true,
};

@Directive({
selector: '[max][formControlName],[max][formControl],[max][ngModel]',
providers: [ MAX_VALIDATOR ],
})
export class TdMaxValidator implements Validator {

private _validator: ValidatorFn;

@Input('max')
set max(max: number) {
this._validator = TdMaxValidator.validate(max);
}

static validate(maxValue: any): ValidatorFn {
return (c: AbstractControl): {[key: string]: any} => {
if (!!Validators.required(c) || !!TdNumberRequiredValidator.validate(c) || (!maxValue && maxValue !== 0)) {
return undefined;
}
let v: number = c.value;
return v > maxValue ?
{ max: {maxValue: maxValue, actualValue: v} } :
undefined;
};
};

validate(c: AbstractControl): {[key: string]: any} {
return this._validator(c);
};
}
40 changes: 40 additions & 0 deletions src/platform/core/validators/min.validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Directive, Input, forwardRef } from '@angular/core';
import { NG_VALIDATORS, Validator, Validators, AbstractControl, ValidatorFn } from '@angular/forms';

import { TdNumberRequiredValidator } from './number-required.validator';

export const MIN_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => TdMinValidator),
multi: true,
};

@Directive({
selector: '[min][formControlName],[min][formControl],[min][ngModel]',
providers: [ MIN_VALIDATOR ],
})
export class TdMinValidator implements Validator {

private _validator: ValidatorFn;

@Input('min')
set min(min: number) {
this._validator = TdMinValidator.validate(min);
}

static validate(minValue: any): ValidatorFn {
return (c: AbstractControl): {[key: string]: any} => {
if (!!Validators.required(c) || !!TdNumberRequiredValidator.validate(c) || (!minValue && minValue !== 0)) {
return undefined;
}
let v: number = c.value;
return v < minValue ?
{ min: {minValue: minValue, actualValue: v} } :
undefined;
};
};

validate(c: AbstractControl): {[key: string]: any} {
return this._validator(c);
};
}
27 changes: 27 additions & 0 deletions src/platform/core/validators/number-required.validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Directive, forwardRef } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl } from '@angular/forms';

export const NUMBER_INPUT_REQUIRED_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => TdNumberRequiredValidator),
multi: true,
};

@Directive({
selector: `[type=number][required][formControlName],
[type=number][required][formControl],
[type=number][required][ngModel]`,
providers: [ NUMBER_INPUT_REQUIRED_VALIDATOR ],
})
export class TdNumberRequiredValidator implements Validator {

static validate(c: AbstractControl): {[key: string]: any} {
return (Number.isNaN(c.value)) ?
{ required: true } :
undefined;
}

validate(c: AbstractControl): {[key: string]: any} {
return TdNumberRequiredValidator.validate(c);
}
}
2 changes: 1 addition & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
"element"
],
"directive-selector-prefix": [
true,
false,
"td"
],
"component-selector-prefix": [ // This will be checked in PR's since we only want `td-` prefix for platform components, not docs not product components.
Expand Down

0 comments on commit 7b7b676

Please sign in to comment.