模型值不会在角度2中自动修剪

时间:2016-05-06 07:13:38

标签: typescript angular

我正在使用角度2表单验证,我在文本框中设置了所需的验证,当我在文本框中输入任何内容时,它显示所需的错误消息它是可以的但是当我只输入空格时它不会显示所需的错误消息,这意味着角度2不修剪模型值。

在角度1.x中,它会自动修剪模型值,但在角度2中,我看不到此功能。

10 个答案:

答案 0 :(得分:11)

好吧,有一个long discussion on github,结果如下:我们必须实现自己的验证器。

这是我到目前为止所使用的:

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);
  }

};

这模仿了字符串输入的标准maxLengthminLengthrequired验证,但修改了代码并将其他功能代理为标准输入。

要使用它,只需导入验证器而不是@angular/forms,例如:

import { FormControl } from '@angular/forms';
import { Validators } from 'path/to/validators';

...
let control = new FormControl('', Validators.compose(
  Validators.required, Validators.minLength(6)
));
...

这可能不会修剪模型,但它解决了请求中指定的验证问题。

答案 1 :(得分:6)

我认为您需要为此实现自定义值访问器。这样的事情:

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);
  }
}

如果要使用此值访问器,请将相应的指令添加到组件中,并在输入中添加trim属性:

@Component({
  (...)
  template: `
    <input type="text" trim/>
  `,
  directives: [ TrimValueAccessor ]
})

有关更多详细信息,请参阅此文章(&#34;与NgModel兼容的组件&#34;部分):

答案 2 :(得分:3)

您只需安装我创建的TrimValueAccessor npm包:

npm install ng-trim-value-accessor --save

然后将其导入您的应用程序:

import { NgModule } from '@angular/core';
import { TrimValueAccessorModule } from 'ng-trim-value-accessor';

@NgModule({
  imports: [
    TrimValueAccessorModule
  ]
})
export class AppModule { }

答案 3 :(得分:3)

只是我的两分钱:

这两个指令都有一个简单的事实,即Angular侦听输入事件以使视图到模型绑定成为存在(不适用于模糊或提交updateOn选项的情况。这些情况也会被处理)。

如果输入事件触发了修剪,则第二个也处理插入位置。

这些指令会使原始的Angular ValueAccessor处理脏和触摸的状态,因此您不会遇到一些奇怪的行为。

ngx-trim-directive演示:https://angular-86w6nm.stackblitz.io,编辑:https://stackblitz.com/edit/angular-86w6nm

答案 4 :(得分:0)

以下是Angular4的代码或从npm安装它。 https://www.npmjs.com/package/ngx-trim

#!/usr/bin/env python
import multiprocessing, os, signal, time, Queue

def do_work():
    print 'Work Started: %d' % os.getpid()
    time.sleep(2)
    return 'Success'

def manual_function(job_queue, result_queue):
    signal.signal(signal.SIGINT, signal.SIG_IGN)
    while not job_queue.empty():
        try:
            job = job_queue.get(block=False)
            result_queue.put(do_work())
        except Queue.Empty:
            pass
        #except KeyboardInterrupt: pass

def main():
    job_queue = multiprocessing.Queue()
    result_queue = multiprocessing.Queue()

    for i in range(6):
        job_queue.put(None)

    workers = []
    for i in range(3):
        tmp = multiprocessing.Process(target=manual_function,
                                      args=(job_queue, result_queue))
        tmp.start()
        workers.append(tmp)

    try:
        for worker in workers:
            worker.join()
    except KeyboardInterrupt:
        print 'parent received ctrl-c'
        for worker in workers:
            worker.terminate()
            worker.join()

    while not result_queue.empty():
        print result_queue.get(block=False)

if __name__ == "__main__":
    main()

BTW,我认为它应该实现ControlValueAccessor而不是扩展DefaultValueAccessor。

答案 5 :(得分:0)

您可以尝试(blur)="modelName= modelName.trim();"。它将在模糊事件时修剪空白区域。您可以根据需要更改事件。

答案 6 :(得分:0)

另一个解决方案可能是将修剪逻辑放在FormControl包装器内。这种方法很简单,不需要第三方依赖性,并且可以与诸如requiredminLength这样的默认验证器一起使用。

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;
    }
}

答案 7 :(得分:0)

我有一个类似的问题。用户会从文本文件或电子邮件中复制和粘贴字符串信息,并偶尔捕获一两个额外的空间。当他们将其粘贴到字段中时,验证程序将失败并显示错误,有时可能会使用户感到困惑。我需要修整粘贴上的值以消除这种混乱。我看过的解决方案是各种自定义值访问器库,但我不想为需要在一两个地方解决的情况而导入库。幸运的是,Angular提供了一些非常简单的选项,可以在短短几行之内完成此操作。

我创建了一个简单的函数来检查提供的值。如果应用的修整后提供的值不为null并且提供的值不同,则我们修补提供的控件的值并触发更新和验证周期。

const TrimValue = (v: string | null, control: AbstractControl ) => {
  if (v && v !== v.trim()) {
    control.patchValue(v.trim());
    control.updateValueAndValidity();
  }
};

有了该功能,我要做的就是订阅控件上的valueChanges发射器并调用TrimValue,以传递发出的值更改和对控件本身的引用。

this.Form = new FormGroup (
  trimMe: new FormControl('', [Validators.required, Validators.pattern(myRegex)])
);
this.Form.get('trimMe').valueChanges.subscribe(
  (val) => TrimValue(val, this.Form.get('trimMe'))
);

我走得更远,并在组件的订阅数组中添加了对valueChanges订阅的引用。然后在ngOnDestroy中,我遍历订阅数组,并在组件完成后取消订阅以清理混乱。

无论如何,此解决方案的好处是可以应用修剪,不会干扰与控件关联的验证器,并且我的用户现在可以放心地粘贴并且不会看到错误,因为有一个或两个空格。它还不需要编写自定义值访问器装饰器/指令或导入其他库来解决可能仅与应用程序中的几个输入字段有关的问题。

答案 8 :(得分:0)

以下指令可与Reactive-Forms一起使用以修剪所有表单字段,而无需在任何地方明确指定它:

@Directive({
  selector: '[formControl], [formControlName]',
})
export class TrimFormFieldsDirective {
  @Input() type: string;

  constructor(@Optional() private formControlDir: FormControlDirective, 
              @Optional() private formControlName: FormControlName) {}

  @HostListener('blur')
  @HostListener('keydown.enter')
  trimValue() {
    const control = this.formControlDir?.control || this.formControlName?.control;
    if (typeof control.value === 'string' && this.type !== 'password') {
      control.setValue(control.value.trim());
    }
  }
}

答案 9 :(得分:-2)

您好在HTML或JSP中尝试这个

(keydown.space)="$event.preventDefault()"

这将不允许文本框中的空格。

这对我有用。