I do have an Observable of Contacts in my onInit method and I also will set the first contact of the Observable into my form. Has anyone a hint how to do this?
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
});
}
Ideally, the form would be in a child component from the one where you get the data. Then you could use the
async
pipe to pass thecontactsObservable
directly to the form, and use the values synchronously.However, in order to do it all in the same
OnInit
hook, the best way would be to provide astartWith
value to yourcontactsObservable
. This will only be viable if you know what the first value will be in every case, and if you know that already, you may as well just instantiate the form control with a valid starting value:You could initialize the form in the subscription as Roland mentioned in the comments, but this would reinitialize your form every time the observable emits a value. Similarly, setting the value of the form control imperatively from within a subscription runs the risk of overwriting user-entered input or other funky behavior depending on how your service works.
Examples of this approach would look something like
Or
Note you could use
setValue
orpatchValue
depending on what you need. But this approach is still faulty because it attempts to ignore the asynchronous nature of the data. And it will overwrite whatever is currently in the input, so if the data is updated while the user is typing, their input will be cleared and replaced, which could be frustrating. Plus you will need to handle clean up of the subscription.The main reason this pattern doesn't work as expected is that you're treating the asynchronous value
contacts
as though it is synchronous. Just by unpacking it in the component and saving the value to a variable doesn't remove the asynchronous nature of the values arriving through the Observable. Check out this resource for more info on that.In my opinion, your best bet is to extract the form into a separate component and take advantage of Angular's
async
pipe to pass your asynchronous data in.You get contacts async. Value can be put when Observable return value.
This worked for me Angular 6.x:
Now the html:
You can use the Form patchValue to set the form, as vincecampanale pointed out better use Smart/Dumb Components pattern with observable then in your component you can set
Why don't you simply put the initialization of the
form
in asubscribe()
?Or you can initialize your form without
contact
, and add it later to theFormGroup
.This will by asyncronous, but you can set an
*ngIf
in your template like this: