可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am using angular 2 form validation, I set required validation on text box, when I enter nothing into textbox it shows required error message it is ok but when I enter only spaces then it does not show required error message, which means angular 2 not trim the model values.
In angular 1.x it automatically trims the model values but in angular 2 I don't see this feature.
回答1:
Well, there is a long discussion on github with the following result: we must implement our own validators.
This is what I use so far:
import { ValidatorFn, AsyncValidatorFn, Validators as V, FormControl } from '@angular/forms';
// the need in this validators is the non-trimming angular standard behavior
// see https://github.com/angular/angular/issues/8503
export class Validators {
public static required(control: FormControl) {
if (!control.value || typeof control.value === 'string' && !control.value.trim()) {
return {
required: true
};
}
return null;
}
public static minLength(length: number): ValidatorFn {
return (control: FormControl) => {
if (!control.value || typeof control.value === 'string' && control.value.trim().length < length) {
return {
minlength: true
};
}
return null;
};
}
public static maxLength(length: number): ValidatorFn {
return (control: FormControl) => {
if (control.value && typeof control.value === 'string' && control.value.trim().length > length) {
return {
maxlength: true
};
}
return null;
};
}
public static pattern(pattern: string): ValidatorFn {
return V.pattern(pattern);
}
public static minAmount(amount: number): ValidatorFn {
return (control: FormControl) => {
if (control.value && control.value.length < amount) {
return {
minamount: true
};
}
return null;
};
}
public static maxAmount(amount: number): ValidatorFn {
return (control: FormControl) => {
if (control.value && control.value.length > amount) {
return {
maxamount: true
};
}
return null;
};
}
public static compose(validators: ValidatorFn[]): ValidatorFn {
return V.compose(validators);
}
public static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn {
return V.composeAsync(validators);
}
};
This mimics the standard maxLength
, minLength
and required
validations for string input but with trimming and proxies other functions to the standard ones.
To use it just import your Validators instead of @angular/forms
one, e.g.:
import { FormControl } from '@angular/forms';
import { Validators } from 'path/to/validators';
...
let control = new FormControl('', Validators.compose(
Validators.required, Validators.minLength(6)
));
...
This maybe does not trim the model but it solves the validation problem specified in the request.
回答2:
I think that you need to implement a custom value accessor for this. Something like that:
const TRIM_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => TrimValueAccessor), multi: true});
@Directive({
selector: 'input[trim]',
host: { '(keyup)': 'doOnChange($event.target)' },
providers: [ TRIM_VALUE_ACCESSOR ]
})
export class TrimValueAccessor extends DefaultValueAccessor {
onChange = (_) => {};
onTouched = () => {};
constructor(private renderer:Renderer) {
}
writeValue(value:any):void {
if (value!=null) {
super.writeValue(value.toString().trim());
}
}
doOnChange(elt) {
let val = elt.value.trim();
this.renderer.setElementProperty(elt, 'value', val);
this.onChange(val);
}
}
When you want to use this value accessor, add the corresponding directive into your component and the trim
attribute on your input:
@Component({
(...)
template: `
<input type="text" trim/>
`,
directives: [ TrimValueAccessor ]
})
See this article for more details (section "NgModel-compatible component"):
- http://restlet.com/blog/2016/02/17/implementing-angular2-forms-beyond-basics-part-2/
回答3:
Just my two cents:
Both directives lie on a simple fact that Angular listens to input event to bring the view-to-model binding into being (not for cases of blur or submit updateOn options. These cases are also handled).
The second one also deals with the caret position if the trim is triggered by input event.
These directives leave the states of dirty and touched to be handled by the original Angular ValueAccessor, so you won't meet with some strange behaviors.
ngx-trim-directive Demo: https://angular-86w6nm.stackblitz.io, editor: https://stackblitz.com/edit/angular-86w6nm
回答4:
You can simply install the TrimValueAccessor npm package that I created:
npm install ng-trim-value-accessor --save
and then import it into your application:
import { NgModule } from '@angular/core';
import { TrimValueAccessorModule } from 'ng-trim-value-accessor';
@NgModule({
imports: [
TrimValueAccessorModule
]
})
export class AppModule { }
回答5:
Here is the code for Angular4 or install it from npm.
https://www.npmjs.com/package/ngx-trim
const TRIM_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
// tslint:disable-next-line:no-forward-ref
useExisting: forwardRef(() => NgxTrimDirective),
multi: true
};
@Directive({
selector: 'input[ngxTrim]',
providers: [TRIM_VALUE_ACCESSOR]
})
export class NgxTrimDirective implements ControlValueAccessor {
_onChange(_: any) { }
_onTouched() { }
registerOnChange(fn: (value: any) => any): void { this._onChange = fn; }
registerOnTouched(fn: () => any): void { this._onTouched = fn; }
constructor (
private _renderer: Renderer2,
private _elementRef: ElementRef
) { }
writeValue(value: any): void {
value && this._renderer.setProperty(this._elementRef.nativeElement, 'value', value);
}
@HostListener('keyup', ['$event.target'])
_onKeyUp(element: HTMLInputElement) {
let val = element.value.trim();
this.writeValue(val);
this._onChange(val);
}
}
BTW, I think it should implement ControlValueAccessor instead of extending DefaultValueAccessor.
回答6:
you can give a try (blur)="modelName= modelName.trim();"
. it will trim white spaces on blur event. you can change event according to your need.
回答7:
Another solution might be to put the trim logic inside a FormControl wrapper. This approach is simple, doesn't require third party dependencies and works with default validators such as required
or minLength
.
export class TrimFormControl extends FormControl {
private _value!: string | null;
get value(): string | null {
return this._value;
}
set value(value: string | null) {
this._value = value ? value.trim() : value;
}
}
回答8:
Hello try this in HTML or JSP
(keydown.space)="$event.preventDefault()"
this will not allow space in text box.
This worked for me.