Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2: Form Build + asynchronous data loading

I have a form created using Form Builder (Angular2 Beta 1, TypoScript), i.e.: there’s something like this in constructor:

this.form = this._formBuilder.group({
    'username': ['', Validators.required],
    'email': ['', Validators.required]
});

The form shows up, everything is nice so far. What I don’t really get is how I handle the binding when I load the data (in this case: a User object) from a remote service (or some other asynchronous loading mechanism).

What I have tried, is:

  • Load the data asynchronously in constructor or ngOnInit. Problem: Throws an exception, even before the loading starts (“Cannot read property 'validator' of undefined …”)
  • Load the data asynchronously in constructor or ngOnInit, but before that create an empty form. Problem: validation does not work.
  • What I would have expected to work: bind the form data to properties of a User object, and set properties of that object. Problem: no exception, but the data does not show up in the form.

I guess there must be some smarter/better way to get this working? I’m rather new to Angular2, so I hope the question is not too dumb …

---- Update ----

First, I forgot to mention that I use ngFormModel in the form – in case it’s important.

And @Thierry: I think that “temporary empty object to bind with the form” is what I tried to do (the 3rd approach mentioned above) but what didn’t work. Precisely, I tried this:

constructor(private _formBuilder:FormBuilder) {
    this.user = new User;
    this.user.username = 'abc';
    this.form = this._formBuilder.group({
        'username': [this.user.username, Validators.required],
    });
}

This displays the username, but it doesn’t even work when I move the line which sets this.user.username to the end of the constructor – which I find pretty surprising, as I would have expected data binding to take care of this.

like image 279
BlueM Avatar asked Feb 03 '16 15:02

BlueM


Video Answer


2 Answers

You could also update individual controls in the FormGroup after data is loaded. For example:

this._http.get('/user/123')
    .map(response => response.json())
    .subscribe(user => {
        this.form.find('username').updateValue(user.username);
        this.form.find('email').updateValue(user.email);
    })

Important part is that you can find control instance in the formGroup one and update its value. Or simple

this.form.controls.username.updateValue(user.username)

would also work.

UPD. Note that in recent versions API has changed so you need to access username with getter:

this.form.get('username').setValue(user.username)
like image 56
dfsq Avatar answered Sep 27 '22 20:09

dfsq


I see several solutions to this:

  • Leverage an *ngIf to display the form only when the data are there
  • Leverage the @CanActivate decorator (if you use routing) to display the component where the form is, only when data are there
  • Use a temporary empty object to bind with the form. When the data are there, you can fill (or override) this object with the data received.

Here is a plunkr: https://plnkr.co/edit/metUkOB7Sqfyr9DtCLR0?p=preview.

Hope it helps you, Thierry

like image 36
Thierry Templier Avatar answered Sep 27 '22 22:09

Thierry Templier