所以。我正在尝试预填充具有异步数据的反应式表单,该表单将发生很大变化。 asyncData $从 AppComponent 馈送到子组件 FormComponent 中的 @input(),该子组件负责处理表单。
在 dataForm $ 的 tap()运算符内进行订阅是我可以< strong> valueChanges 工作并实际发出值,但嵌套订阅是不行的,因此我想找到一个更好/更干净的解决方案,避免这种情况-最好使用可观察对象。可能是我缺少明显的东西
有人有建议吗?
表单本身必须是可观察的
<div>
<app-form [asyncData]="asyncData$ | async"></app-form>
</div>
export class AppComponent implements OnInit {
title = 'observableForm';
asyncData$: ReplaySubject<Data> = new ReplaySubject<Data>(1);
ngOnInit(): void {
setTimeout(() => this.asyncData$.next( {
id: 42,
name: 'Han Solo',
heShotFirst: true
} as Data), 2000);
}
}
<div *ngIf="(dataForm$ | async) as dataForm">
<form [formGroup]="dataForm" style="padding: 5rem; display: grid; place-items: center;">
<div>
<label>
Id
<input type="text" [formControlName]="'id'">
</label>
<label>
Name
<input type="text" [formControlName]="'name'">
</label>
<br>
<label>
He shot first
<input type="radio" [value]="true" [formControlName]="'heShotFirst'">
</label>
<label>
He did not
<input type="radio" [value]="false" [formControlName]="'heShotFirst'">
</label>
</div>
</form>
<div *ngIf="(lies$ | async) === false" style="display: grid; place-items: center;">
<h1>I Must Not Tell Lies</h1>
</div>
</div>
export class FormComponent implements OnInit, OnDestroy {
@Input() set asyncData(data: Data) { this._asyncData$.next(data); }
_asyncData$: ReplaySubject<Data> = new ReplaySubject<Data>(1);
dataForm$: Observable<FormGroup>;
valueChangesSub$: Subscription;
lies$: Subject<boolean> = new Subject<boolean>();
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.dataForm$ = this._asyncData$.pipe(
map(data => {
return this.fb.group({
id: [data?.id],
name: [data?.name],
heShotFirst: [data?.heShotFirst]
});
}),
tap(form => {
if (this.valueChangesSub$ != null) {
this.valueChangesSub$.unsubscribe();
}
return form.valueChanges.subscribe(changes => {
console.log(changes)
this.lies$.next(changes.heShotFirst);
});
})
);
}
ngOnDestroy(): void {
this.valueChangesSub$.unsubscribe();
}
}
答案 0 :(得分:1)
我不确定为什么表格需要是可观察的。相反,我使用OnChanges
监视父组件的更改,而使用valueChanges
监视表单的更改。
这是结果代码:
import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges } from "@angular/core";
import { ReplaySubject, Observable, Subscription, Subject } from "rxjs";
import { Data } from "./data";
import { FormGroup, FormBuilder } from "@angular/forms";
import { map, tap } from "rxjs/operators";
@Component({
selector: "app-form",
templateUrl: "./form.component.html"
})
export class FormComponent implements OnInit, OnDestroy, OnChanges {
@Input() asyncData: Data;
dataForm$: Observable<FormGroup>;
dataForm: FormGroup;
valueChangesSub: Subscription;
lies$: Subject<boolean> = new Subject<boolean>();
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.dataForm = this.fb.group({
id: "",
name: "",
heShotFirst: false
});
this.valueChangesSub = this.dataForm.valueChanges.subscribe(changes => {
console.log(changes);
this.lies$.next(changes.heShotFirst);
});
}
ngOnChanges(changes: SimpleChanges) {
let currentValue: Data = changes.asyncData.currentValue;
console.log("changes", currentValue);
if (currentValue !== null) {
this.dataForm.patchValue({
id: currentValue.id,
name: currentValue.name,
heShotFirst: currentValue.heShotFirst
});
}
}
ngOnDestroy(): void {
this.valueChangesSub.unsubscribe();
}
}
我在这里对此有个狂喜:https://stackblitz.com/edit/angular-async-form-deborahk
使用OnChanges
,每次向父级流中发送新值时,子级组件都会收到通知。 (我尝试通过在父组件中设置第二个setTimeout
来模拟这一点。)
然后,表单上的valueChanges
似乎可以正常工作。
如果这不是您想要的,请随时进行堆栈闪电式调试,并根据需要对其进行修改以演示您的问题。
答案 1 :(得分:0)
如何设置两个Observable?
this.dataForm$ = this._asyncData$.pipe(
map(data => this.fb.group({
id: [data?.id],
name: [data?.name],
heShotFirst: [data?.heShotFirst]
})),
);
this.lies$ = this.dataForm$.pipe(
switchMap(form => form.valueChanges),
map(changes => changes.heShotFirst),
);