我有一个基本的表单控件,订阅了valueChanges。
@Component({
selector: 'my-app',
template: `
<input [formControl]="control" />
<div>{{ name$ | async | json }}</div>
`
})
export class AppComponent implements OnInit {
name$: Observable<string>;
control;
constructor(private builder: FormBuilder) {
this.control = this.builder.control('');
}
ngOnInit() {
this.name$ = this.control.valueChanges
.pipe(
map((name) => {
console.log('fired', name)
return name;
})
);
this.control.setValue('2');
}
}
当我调用setValue时,观察者没有收到任何通知。似乎异步管道不起作用。如果我将setValue包装在setTimeout中,则可以正常工作。为什么会这样呢?
我还试图添加shareReplay(),该方法也无效。
答案 0 :(得分:0)
这个问题的解决方案
this.control.setValue('2'); // I move any changes at the top for startWith operater
this.name$ = this.control.valueChanges
.pipe(
startWith(this.control.value),
map((name) => {
console.log('fired', name)
return name;
})
);
另一种无需使用async
运算符即可工作的方法,这意味着我已在控制值更改为“ 2”之前订阅了值更改,并且稍后已捕获所有更改
this.control.valueChanges
.pipe(
map((name) => {
console.log('fired', name)
return name;
})
)
.subscribe ( v => this.value = v )
模板
{{value}}
为什么问题中带有async的示例不起作用,异步操作符将订阅可观察的对象,但是在异步订阅时,控件的当前值将为'2',因此没有更改为何第一个值将为不会作为表单控件的更改发出,可观察到的另一件事是懒惰的,因此当您订阅时,您将获得该值,任何更改之前都不会被看到
答案 1 :(得分:0)
如果你想在 Angular 中观察一个 from 控制值的通用解决方案:
this.value$ = defer(() => {
return this.control.valueChanges.pipe(startWith(this.control.value));
});
通过使用 defer
,您可以确保当您的 observable 被订阅时,您的 startWith 值将是您表单的实际值。如果您没有使用 defer
,您的 startWith 值将只是您的 observable 被创建(未订阅)时表单的值。
如果你想在你的应用程序中重用它,你可以将该逻辑放在一个 utils 函数中:)
// utils.ts
export function observeControlValue$(formControl: AbstractControl): Observable<any> {
return defer(() => {
return formControl.valueChanges.pipe(startWith(formControl.value));
});
}
// component.ts
this.value$ = observeControlValue$(this.control);
答案 2 :(得分:-1)
当您从ngOnInit
调用视图时,尚未初始化视图的原因(HTML标记)尚未初始化。
您需要将其添加到ngAfterViewInit()
:
import AfterViewInit from '@angular/core';
export class AppComponent implements AfterViewInit{
ngAfterViewInit() {
this.name$ = this.control.valueChanges
.pipe(
map((name) => {
console.log('fired', name)
return name;
})
);
this.control.setValue('2');
}
}
尽管您需要进行测试,但我没有
答案 3 :(得分:-1)
如果要使用反应形式,则应使用FormControl而不是FormBuilder。
您的控件应该这样初始化:
export class AppComponent implements OnInit {
public control = new FormControl('');
HTML为:<input type="text" [formControl]="control">
然后,您无需使用Observable<string>
即可
<div>{{ control.value | json }}</div>
有关详细信息,请参见ReactiveForm文档:https://angular.io/guide/reactive-forms