Angular:指令中的updateValueAndValidity

时间:2018-01-27 05:23:31

标签: angular angular2-forms angular2-directives

我有一个指令,如果输入值是整数,则在模糊时附加小数。以下是实施。

import { Directive, ElementRef, Input, OnInit, HostListener, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Directive({
  selector: '[price]',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => PriceDirective),
      multi: true
    }
  ]
})
export class PriceDirective implements ControlValueAccessor {

  constructor(private el: ElementRef) { }

  // ControlValueAccessor interface
  private _onChange = (_) => { };
  private _onTouched = () => { };

  @HostListener('blur', ['$event'])
  input(event) {
    !!event.target.value ? $(this.el.nativeElement).val(Number(event.target.value).toFixed(2)) : $(this.el.nativeElement).val(null);

    this._onChange(parseFloat(event.target.value));
    this._onTouched();
  }
  writeValue(value: any): void {
    !!value ? $(this.el.nativeElement).val(Number(value).toFixed(2)) : $(this.el.nativeElement).val(null);
  }

  registerOnChange(fn: (_: any) => void): void { this._onChange = fn; }
  registerOnTouched(fn: any): void { this._onTouched = fn; }

}

事情按预期工作。

但是,由于Angular在以编程方式更改值时不会触发验证,因此不会验证具有此指令的文本框。

在这种情况下,如何通过其他方式启用验证,而不是将control引用作为输入传递给指令并在其上调用updateValueAndValidity,或者在{{updateValueAndValidity上调用input。 1}}或blur

如果有人建议我从指令本身触发验证,那将会很棒。

3 个答案:

答案 0 :(得分:1)

我以这种方式解决了同样的问题。 这是我的第一种方法。

while

但是它不会触发validate事件。因此,我得到了 update() { // ... const el = this.el.nativeElement; const reg = new RegExp(this.textMaskConfig.replacement); el.value = this.prevStr.replace(reg, this.currentChar); // ... } 组件并使用了NgControl方法。

setValue()

答案 1 :(得分:0)

我解决了我认为相同的问题。当像您的示例中那样在nativeElement上设置值或将HostBinding设置为@HostBinding('value') public value: string;之类的值时,无法触发验证。但是当我通过ngModelChange设置值时,可以触发验证:

import { Directive, Input, HostListener, Output, EventEmitter } from '@angular/core';

@Directive({
    selector: '[appPrice]',
})
export class PriceDirective {
    @Output()
    public ngModelChange: EventEmitter<any> = new EventEmitter();

    @HostListener('blur', ['$event.target.value'])
    public formatANumber(value) {
        const cleanedValue = Number(value).toFixed(2);
        this.ngModelChange.emit(cleanedValue);
    }
}

答案 2 :(得分:0)

我不清楚您要添加什么验证。据我了解,您想从指令中获取形式的输入元素并根据某种逻辑对其进行操作。我将向您展示使用rx.js的一种方法,并根据您的验证逻辑,您可以使用相应的运算符。

在生成的指令文件中:

import { Directive, ElementRef } from '@angular/core';
import { NgControl } from '@angular/forms';
import { map } from 'rxjs/operators';

@Directive({
  selector: '[appPrice]',
})

export class PriceDirective {
  // dependency injection for ElementRef has to set in the constructor
  constructor(private el: ElementRef, private controlName: NgControl) {
    console.log(this.el);
    console.log('controlName', controlName);
    // this returns FormControlName (not FormControl) obj. it has name property that tells u which formCpntrol element u r on.
    // FormContolName class binds the FormControl to the "input" element. FormControlName has no direct reference to FormGroup
    // controlName is bound to input element's formGroup's FormGroup
  }
  ngOnInit() {
    console.log(this.controlName.control);
    // this returns the name of the formControl
    console.log(this.controlName.control.parent);
    // this.controlName.control.parent takes us to the FormGroup
    // this.controlName.control.parent returns observable. valueChanges watches all the formControls that you defined. if you have "a","b","c" formControls
    // with pipe() you can add operators to modify the value
    this.controlName.control.parent.valueChanges
      .pipe(map(({ a, b, c }) => // add Some Logic here))
      .subscribe((value) => {
        if (here is True) {
          this.el.nativeElement.classList.add('close');
        } else {
          this.el.nativeElement.classList.remove('close');
        }
      });
  }
}