Ionic 实现ControlValueAccessor的可重用组件在以编程方式更改值时触发onChange

xytpbqjk  于 2022-12-16  发布在  Ionic
关注(0)|答案(1)|浏览(132)

我正在开发一个移动的应用程序,使用离子Angular 以及React形式
我有一个可重用的组件来输入电话号码,这个组件实现了ControlValueAccessor接口。另外,这个组件下面有一个按钮,用来从联系人列表中选择电话号码,当我以编程方式设置这个值时,onChange事件被触发两次

可重复使用的组件

export class PhoneNumberFormControl implements ControlValueAccessor {

  value: string;

  /**
   * With this I change the value programmatically.
   */
  set newValue(newValue: T) {
    if (newValue !== this.value) {
      this.value = newValue;
      this.onChange(newValue); // <= Notify the parent form
    }
  }

  onChange = (newValue: T) => {};
  onTouched = () => {};

  constructor(
    @Optional() @Self() public ngControl: NgControl
  ) {
    if (ngControl != null) {
      ngControl.valueAccessor = this;
    }
  }

  writeValue(value: T): void {
    if (value !== this.value) {
      this.value = value;
    }
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
  }

  async openModal() {
    // Logic to open a modal
    string phoneNumber = '7871234567';

    if (phoneNumber) {
      // 1. Changing the value programmatically, onChange is called, see setter above
      this.newValue = phoneNumber;
      // 2. Let the parent know that the input was touched because you have used the modal. This is wrong?
      this.onTouched();
    }
  }

}

模板

<ion-input [(ngModel)]="value"
           (ionBlur)="onTouched()"
           (ionChange)="onChange($event.target.value)">
</ion-input>

<ion-button (click)="openModal()">
  Select from contacts
</ion-button>

问题:

ion-inputionChange事件,因为你可以手动写一个电话号码。到目前为止很好。
如果你打开模态来选择一个电话号码,ionChange会被调用来让父节点知道这个变化,但是ion-inputionChange也会被调用,因为这是一个变化。

示例

  • 模板部分被省略,因为它不重要。*
export class ExamplePage implements OnInit {

      form: FormGroup;
    
      constructor(
        private fb: FormBuilder
      ) {
      }
    
      ngOnInit(): void {
        this.form = this.fb.group({
          phoneNumber: [null, Validators.required]
        });
        this.form.get('phoneNumber').valueChanges.subscribe(() => this.doLogic());
      }
    
      // This is being called twice when choosing a phone number from the modal
      doLogic() {
        console.log('I was called');
      }
    
    }

我试过几种方法,但结果都一样。
我的目标是知道如何正确地实现这一点,只通知父母一次。

mlmc2os5

mlmc2os51#

经过一段时间的调试问题,我发现我忘记了一件重要的事情的输入和事件的变化。
我有这个:

async openModal() {
  string phoneNumber = '7871234567';

  if (phoneNumber) {
    this.newValue = phoneNumber;
    this.onTouched();
  }
}

setter this.newValue = phoneNumber正在调用onChange(),让它知道更改的父进程,但在此之后,ion-input还有(ionChange)="onChange($event.target.value)事件,它再次通知父进程。
修复程序只是这样做:

async openModal() {
   string phoneNumber = '7871234567';
    
   if (phoneNumber) {
      this.value = phoneNumber;
   }
}

这为ion-input设置了一个新值,ion-input通过ionChange()事件通知父进程,这样父进程只被通知一次。
我不知道这是不是推荐的方法,但它确实有效。

相关问题