[英]Angular 5 - Observable - set first value of Observable into formgroup
我的 onInit 方法中确实有一个 Observable 的 Contacts,我还将 Observable 的第一个联系人设置到我的表单中。 有没有人提示如何做到这一点?
ngOnInit() {
let contactsObservable: Observable<Contact[]> =
this.contactService.getAllContacts();
contactsObservable.subscribe(contacts => {
this.contacts = contacts;
});
this.form = this.fb.group({
// this.contacts[0] does not work
contact: [this.contacts[0], [Validators.required]] // how to get contact[0] into form for presetting
});
}
您得到的联系人异步。 可观察值返回时可以放入值。
ngOnInit() {
this.form = this.fb.group({
contact: ['', [Validators.required]]
});
let contactsObservable: Observable<Contact[]> =
this.contactService.getAllContacts();
contactsObservable.subscribe(contacts => {
this.contacts = contacts;
this.form.controls['contact'].setValue(this.contacts[0])
});
}
理想情况下,表单应位于获取数据的子组件中。 然后,您可以使用async
管道将contactsObservable
直接传递给表单,并同步使用这些值。
然而,为了做到这一切在相同OnInit
挂钩,最好的办法是提供一个startWith
价值,你的contactsObservable
。 仅当您知道每种情况下的第一个值是什么才可行,并且如果已经知道第一个值,那么还可以使用有效的起始值实例化表单控件:
this.form = this.fb.group({
contact: [[ // some value ], [Validators.required]]
});
您可以像注释中提到的Roland一样在订阅中初始化表单,但是这会在每次Observable发出值时重新初始化表单。 同样,从预订中强制设置表单控件的值会带来覆盖用户输入的输入或其他时髦行为的风险,具体取决于服务的工作方式。
这种方法的例子看起来像
contactsObservable.subscribe(contacts => {
this.form = this.fb.group({
contacts: [contacts, [...Validators]]
})
});
要么
this.form = this.fb.group({
contacts: [[], [...Validators]]
});
contactsObservable.subscribe(contacts => {
this.form.get('contacts').setValue(contacts);
});
请注意,您可以根据需要使用setValue
或patchValue
。 但是这种方法仍然有缺陷,因为它试图忽略数据的异步特性。 并且它将覆盖输入中当前的内容,因此,如果在用户键入时更新数据,则将清除并替换其输入,这可能会令人沮丧。 另外,您将需要处理订阅的清理。
此模式无法按预期工作的主要原因是您将异步值contacts
视为同步对象。 仅通过将其解压缩到组件中并将值保存到变量中,并不能消除通过Observable到达的值的异步性质。 请查看此资源以获取更多信息。
我认为,最好的选择是将表单提取到一个单独的组件中,并利用Angular的async
管道传递异步数据。
您可以使用Form patchValue来设置表单,因为vincecampanale指出最好使用可观察的Smart / Dumb Components模式,然后在您的组件中进行设置
@Input() set contactsList(contacts: any[]) {
if (contacts) {
this.form.patchValue({
contact: contacts[0]
});
}
}
您为什么不简单地将form
的初始化放在subscribe()
?
ngOnInit() {
// ...
// .take(2) to ensure that it will run only for the first value:
contactsObservable.take(1).subscribe(contacts => {
this.form = this.fb.group({contact: [this.contacts[0], Validators.required]];
});
// ...
}
或者,您可以不contact
而初始化表单,然后将其添加到FormGroup
。
这将是异步的,但是您可以在模板中设置*ngIf
,如下所示:
<form *ngIf="form" ...>...</form>
这对我来说适用于Angular 6.x:
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
@Input() artist: Artist;
artistForm: FormGroup;
constructor(private route: ActivatedRoute, private artistService: ArtistService, private location: Location, private fb: FormBuilder) { this.createForm(); }
ngOnInit() {
this.getArtist();
}
createForm(){
this.artistForm = this.fb.group({
ArtistName: ['', Validators.required]
});
}
getArtist(): void{
const id = +this.route.snapshot.paramMap.get('id');
this.artistService.getArtist(id).pipe(tap(artist => this.artistForm.setValue({ArtistName: artist.ArtistName}))).subscribe(artist => {
artist = this.artist;
});
}
现在的HTML:
<h2>Artist Information</h2>
<form [formGroup]="artistForm">
<div class="form-group">
<label class="center-block">Artist Name:
<input class="form-control" formControlName="ArtistName">
</label>
</div>
你可以做这样的事情。
class MyComponent {
ngOnInit() {
this.form = this.fb.group({
contact: ['', [Validators.required]]
});
let contactsObservable: Observable<Contact[]> =
this.subscription = this.contactService.getAllContacts()
.pipe(take(1))
.subscribe(contacts => {
this.contacts = contacts;
this.form.controls['contact'].setValue(this.contacts[0])
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
重要提示:记得取消订阅。
使用 take(1) 时无需取消订阅,我不喜欢您在某些 cas 中的方法(例如,当您第一次使用 ngrx 和 dispatch 时),第一个观察到的值将是“null”或空列表您仍在等待请求响应。
同样,在 NGRX 中,您的商店存在但首先是空的。 每次你的 observable 实际上是一个 BehaviuourSubject 时都会出现这种情况
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.