使用从 ControlValueAccessor 控件的 valueChanges 创建的可观察对象时,异步管道不起作用

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

我有一个 ControlValueAccesor 和一个 FormControl。我需要从控件的 valueChanges 创建一个新的可观察对象,并通过 AsyncPipe 在模板中使用它。因此,在 CVA 的 writeValue 中,我使用 setValue() 更新表单控件的值。

 public isOdd$ = new Observable<boolean>();
 nestedFc = new FormControl([null]);

 writeValue() {
   this.nestedFc.setValue(22);
 }
 ngOnInit() {
    this.isOdd$ = this.nestedFc.valueChanges.pipe(
      map((value) => value % 2 !== 0)
    );
 }
<span> <input [formControl]="nestedFc"/> </span>
<span *ngIf="{value: isOdd$ | async} as context"> {{context.value}}</span>

问题是,第一次调用 writeValue 时会触发 valueChanges,但异步管道不会“看到”这些更改,因此视图不会显示更新。

围绕此有几个 GitHub 问题:ng 11:patchValue、valueChanges 和异步管道https://github.com/angular/angular/issues/40826.

基于上一个,我创建了一个 stackblitz 来重现该问题。如果 writeValue 使用 setTimeout 来修补表单控件的值,则会触发 valueChanges 并且异步管道“看到”更改。

这是正确的吗?除了使用setTimeout真的没有其他办法吗?

angular controlvalueaccessor async-pipe angular-controlvalueaccessor
2个回答
0
投票

问题是, writeValue 在 ngOnInit 之前被调用,并且您对值的订阅发生了变化。 Observables 仅获取订阅后发出的值,除非它们有

shareReplay
管道。

因此您需要添加

setTimeout
或使用不同的钩子(如
ngAfterViewInit
)来设置值。


0
投票

当您修补

custom form control
内的值时,您应该更喜欢在外部表单上设置该值,而不是在自定义表单控件内,这基本上可以消除错误。

您应该始终更喜欢在加载时修补自定义控件外部的值。

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-bug-show',
  template: `
    <app-child [formControl]="fc"></app-child>
  `,
})
export class BugShowComponent {
  fc = new FormControl(3);
}

要消除

async
bug,只需在
ngOnInit
钩子末尾手动调用更改检测即可。

  ngOnInit() {
    console.log('on init');
    ...
    this.cdr.detectChanges(); // <- changed here
  }

Stackblitz 演示

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