Angular自定义控件:在响应式表单中不触发更改事件。

huangapple go评论63阅读模式
英文:

Angular Custom Control: change event isn't triggered in reactive form

问题

这段代码曾经运行良好,直到我发现它出了问题。我面临的问题如下:

我有一个抽象值访问器类,被多个自定义表单控件继承。它的结构如下:

@Directive()
export abstract class AbstractInputComponent implements OnChanges {

  @Input() public isReadOnly = false;

  protected innerValue: unknown = null;
  public registerOnChange(fn: any) { this.propagateChange = fn; }
  public registerOnTouched(fn: any) { this.propagateTouch = fn; }
  public propagateChange = (_: any) => { };
  public propagateTouch = (_: any) => { };

  public ngOnChanges(): void {
    if ( this.isReadOnly ) {
        this.propagateChange(this.value);
    }
    this.cdr.detectChanges();
  }

  public get value(): any {
    return this.innerValue;
  };

  @Input() public set value(value: any) {
    if ( value !== undefined ) {
        this.writeValue(value);
        this.propagateChange(this.innerValue);
        this.propagateTouch(true);
    }
  }

  public writeValue(value: any): void {
    if (value !== this.innerValue) {
        this.innerValue = this.normalize(value);
    }
  }
}

其中一个自定义控件看起来像这样:

@Component({
    selector: 'ultim-checkbox',
    encapsulation: ViewEncapsulation.None,
    templateUrl: './checkbox-input.component.html',
    providers: [
        {
          provide: NG_VALUE_ACCESSOR,
          useExisting: forwardRef( () => CheckboxInputComponent ),
          multi: true
        },
        {
          provide: NG_VALIDATORS,
          useExisting: forwardRef( () => CheckboxInputComponent ),
          multi: true
        }
    ]
})
export class CheckboxInputComponent extends AbstractInputComponent implements ControlValueAccessor, Validator  {
   constructor ( protected cdr: ChangeDetectorRef ) {
       super(cdr);
   }
}

然后,在父模板中,我有以下类似的标记:

<ultim-checkbox formControlName="isAdmin"
    (change)="setAdmin()"></ultim-checkbox>

setAdmin() 方法从未被调用。有任何想法为什么会这样吗?

Angular 11
Typescript 5.1.6

英文:

This was working fine for some time until I found out it wasn't. The issue I face is the following.

I have an abstract value accessor class which is being extended by multiple custom form controls. It looks like this:

@Directive()
export abstract class AbstractInputComponent implements OnChanges {

  @Input() public isReadOnly = false;

  protected innerValue: unknown = null;
  public registerOnChange(fn: any) { this.propagateChange = fn; }
  public registerOnTouched(fn: any) { this.propagateTouch = fn; }
  public propagateChange = (_: any) =&gt; { };
  public propagateTouch = (_: any) =&gt; { };

  public ngOnChanges(): void {
    if ( this.isReadOnly ) {
        this.propagateChange(this.value);
    }
    this.cdr.detectChanges();
  }

  public get value(): any {
    return this.innerValue;
  };

  @Input() public set value(value: any) {
    if ( value !== undefined ) {
        this.writeValue(value);
        this.propagateChange(this.innerValue);
        this.propagateTouch(true);
    }
  }

  public writeValue(value: any): void {
    if (value !== this.innerValue) {
        this.innerValue = this.normalize(value);
    }
  }
}

One of the custom controls looks like this:

@Component({
	selector: &#39;ultim-checkbox&#39;,
	encapsulation: ViewEncapsulation.None,
	templateUrl: &#39;./checkbox-input.component.html&#39;,
	providers: [
		{
		  provide: NG_VALUE_ACCESSOR,
		  useExisting: forwardRef( ()=&gt; CheckboxInputComponent ),
		  multi: true
		},
		{
		  provide: NG_VALIDATORS,
		  useExisting: forwardRef( ()=&gt; CheckboxInputComponent ),
		  multi: true
		}
	  ]
})
export class CheckboxInputComponent extends AbstractInputComponent implements ControlValueAccessor, Validator  {
   constructor ( protected cdr: ChangeDetectorRef ) {
	   super(cdr);
   }
}

So, then in the big parent template I have this kind of markup:

&lt;ultim-checkbox formControlName=&quot;isAdmin&quot;
    (change)=&quot;setAdmin()&quot;&gt;&lt;/ultim-checkbox&gt;

And setAdmin() method never gets called. Any ideas why?

Angular 11
Typescript 5.1.6

答案1

得分: 1

问题出在你如何绑定父模板中的 (change) 事件。由于你正在使用 Angular 的响应式表单和 formControlName,正确的事件监听更改的事件是 (ngModelChange) 事件,而不是标准的 (change) 事件。

这是你应该如何修改父模板的方式:

<ultim-checkbox formControlName="isAdmin" (ngModelChange)="setAdmin()"></ultim-checkbox>
英文:

The problem lies in how you're binding the (change) event in the parent template. Since you're using Angular's reactive forms with formControlName, the correct event to listen for changes is the (ngModelChange) event, not the standard (change) event.

Here's how you should modify the parent template:

&lt;ultim-checkbox formControlName=&quot;isAdmin&quot; (ngModelChange)=&quot;setAdmin()&quot;&gt;&lt;/ultim-checkbox&gt;

huangapple
  • 本文由 发表于 2023年7月20日 21:41:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76730507.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定