如何防止 Angular 表单在父组件中捕获事件之前必须发出两次?

问题描述 投票:0回答:1

我有一个 Angular 应用程序,其中包含一个允许用户增加数量的表单。

  • 当用户单击“添加”按钮时加载表单,并预填充数量 1。
  • FormControl 对象从父级传递到表单中,当客户增加/减少数量时,它会通过 patchValue 进行更新,并且这应该发出一个事件,可以使用对 valueChanges 的订阅在父级中捕获该事件。
  • 但是由于我无法确定的原因,在父组件订阅注册事件之前,数量必须增加两次
  • 注册第一个事件后,所有后续增量/减量都会按预期工作。

这里有一个最小的 StackBlitz 工作示例

这是上面示例中的父组件:

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [Counter],
  template: `<h1>Counter</h1>
  <Counter [value]="1" [control]="qtyForm"></Counter>
  <p>Value from form emission:</p>
  <p>{{newQuantity}}</p>`,
})
export class App {
  newQuantity!: number | null;
  qtyForm = new FormControl(0, [Validators.required, Validators.max(99)]);

  ngAfterViewInit() {
    this.updateCustomQuantity();
  }
  updateCustomQuantity() {
    this.qtyForm.valueChanges
      .subscribe((qty) => {
        this.newQuantity = qty;
      });
  }
}

和子(计数器)组件:

@Component({
  selector: 'Counter',
  standalone: true,
  imports: [MatFormFieldModule, MatInputModule, ReactiveFormsModule],
  template: `
    <p>Need to increment/decrement twice before form emits:</p>
    <button (click)="decrement()">Subtract</button>
    <mat-form-field>
      <input matInput [formControl]="control">
    </mat-form-field>
    <button (click)="increment()">Add</button>
  `,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => Counter),
      multi: true,
    },
  ],
  encapsulation: ViewEncapsulation.None,
})
export class Counter implements ControlValueAccessor, OnInit {
  formControlDirective!: FormControlDirective;
  currentValue!: number | null | undefined;
  @Input() value!: number;
  @Input() control!: FormControl;
  ngOnInit() {
    this.control.patchValue(this.value, { emitEvent: false });
    this.currentValue = this.value;
  }
  
  increment() {
    const currentValue = this.control.value;
    this.control.patchValue(currentValue + 1);
  }

  decrement() {
    const currentValue = this.control.value;
    this.control.patchValue(currentValue - 1);
  }
...
}

我不得不承认我对此有点困惑。从 ngOninit() 中删除 emitEvent: false 没有任何效果。

angular-material angular-forms
1个回答
0
投票

解决方法是将

ngAfterViewInit
更改为
ngOnInit
并且工作正常,至于为什么
ngAfterViewInit
没有在加载时触发对我来说是个谜,也许其他人可以解释这一点,或者你可以提出Angular github 页面中的票证!

import { Component, AfterViewInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FormControl, Validators } from '@angular/forms';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { Counter } from '../Counter';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [Counter, CommonModule, ReactiveFormsModule, FormsModule],
  template: `<h1>Counter</h1>
  <Counter [value]="0" [control]="qtyForm"></Counter>
  <p>Value from form emission:</p>
  <p>{{newQuantity}}</p>`,
})
export class App {
  newQuantity!: number | null;
  qtyForm = new FormControl(1, [Validators.required, Validators.max(99)]);

  ngOnInit() {
    console.log('asdf');
    this.updateCustomQuantity();
  }

  updateCustomQuantity() {
    console.log(this.qtyForm.value);
    this.newQuantity = this.qtyForm.value;
    this.qtyForm.valueChanges.subscribe((qty) => {
      this.newQuantity = qty;
    });
  }
}

bootstrapApplication(App);

堆栈闪电战

© www.soinside.com 2019 - 2024. All rights reserved.