Angular:来自指令的 updateValueAndValidity

Posted

技术标签:

【中文标题】Angular:来自指令的 updateValueAndValidity【英文标题】:Angular: updateValueAndValidity from directive 【发布时间】:2018-07-06 11:20:35 【问题描述】:

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

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 或在inputblur 上调用updateValueAndValidity 之外,我如何才能启用验证。

如果有人建议我一种从指令本身触发验证的方法,那就太好了。

【问题讨论】:

好问题,我也有同样的问题。点赞! 【参考方案1】:

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

  update() 

    // ...

    const el = this.el.nativeElement;
    const reg = new RegExp(this.textMaskConfig.replacement);

    el.value = this.prevStr.replace(reg, this.currentChar);

    // ...

  

但它不会触发 validate 事件。所以我得到了NgControl 组件并使用了setValue() 方法。

  constructor(private el: ElementRef, private ctrl: NgControl)    
  

  @HostListener('keydown', ['$event']) onKeyDownHandler(e) 
    this.ctrl.control.setValue(value);
  

【讨论】:

【参考方案2】:

我解决了我认为相同的问题。当我像在您的示例中那样在 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);
    

【讨论】:

【参考方案3】:

我不清楚您要添加什么验证。据我了解,您希望从指令中获取表单的输入元素并根据某些逻辑对其进行操作。我将向您展示一种使用 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');
        
      );
  

【讨论】:

以上是关于Angular:来自指令的 updateValueAndValidity的主要内容,如果未能解决你的问题,请参考以下文章

来自另一个模块的组件上的 Angular 指令输入会导致错误

单击时来自组件的Angular2触发指令

如何在angular4中为来自ts的反应形式应用自定义指令?

AngularJs将来自单独文件的多个指令注入一个公共模块

我可以在 Angular ng-style 指令中使用来自 API 调用的数据吗?

vuex 未知本地变异类型:updateValue,全局类型:app/updateValue。突变不起作用