[英]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.