Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs 2 component property undefined

Tags:

angular

I have been following the Angular 2 Development Guide. I ran into this problem while doing 9 Routing and Navigation Milestone 3

I added a function getCrisis that takes one parameter sn. The function returns a Promise<Crisis> asynchronously.

crisis.service.ts

import {Injectable} from 'angular2/core';
import {CRISES} from './mock-crisises';

@Injectable()
export class CrisisService {

    getCrisises() {
        return Promise.resolve(CRISES);
    }

    // the | string token is a Pipe
    getCrisis(sn: number | string) {
        return Promise.resolve(CRISES).then(cries => cries.filter(c => c.serialNumber === +sn)[0]);
    }
}

crisis-form.component.ts that calls getCrisis on ngOnInit

export class CrisisFormComponent implements OnInit, CanDeactivate{

    public model: Crisis;
    public origin: Crisis;

    submitted = false;
    active = true;

    constructor(
        private _service: CrisisService,
        private _dialog: DialogService,
        private _router: Router,
        private _routeParams: RouteParams
    ) { }

    ngOnInit() {
        let sn = +this._routeParams.get('sn');
        this._service.getCrisis(sn).then(crisis => {
            if (crisis) {
                console.log(crisis) // debug output
                this.origin = new Crisis(crisis);
                this.model = crisis;
            }
            else {
                this.gotoCrisisCenter();
            }
        });
    }

crisis-form.component.html

<h1>Crisis Form</h1>
<form *ngIf="active" (ngSubmit)="onSubmit()" #crisisForm="ngForm">
    {{diagnostic}}
    <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" required [(ngModel)]="model.name" ngControl="name" #name="ngForm">
        <div [hidden]="name.valid || name.pristine" class="alert alert-danger">
            Name is required
        </div>
    </div>

    <button type="submit" class="btn btn-default" [disabled]="!crisisForm.form.valid">Submit</button>
</form>

I got this exception when loading the crisis-form component. The input element is bound to this.model.name. It seems the framework found this.model as undefined for some reason. I added some console debug outputs in the ngOnInit function. They appear in the button of the console after the exception message. The Promise did got resolved correctly and the crisis object is assigned to this.model property correctly.

But the fact that the framework finds this.model undefined and the order of these messages appears in the console. Is it possible that when the framework evaluates the binding, this.model has not been assigned yet due to the async process, which causes the exception? Then, the Promise is resolved and assigned to this.model, and the debug messages are printed to the console.

The live sample from Angular does same thing but they dont get the exception. See their sample in app/crisis-centre/crisis-detail.component.ts line 37-46.

Any help will be appreciated. Thank you.

Error

like image 491
Frank Liu Avatar asked Dec 19 '22 19:12

Frank Liu


2 Answers

When load html, model still null.

Please update to

<div class="form-group" *ngIf="model">
        <label for="name">Name</label>
        <input type="text" class="form-control" required [(ngModel)]="model.name" ngControl="name" #name="ngForm">
        <div [hidden]="name.valid || name.pristine" class="alert alert-danger">
            Name is required
        </div>
    </div>
like image 148
Zilong Wang Avatar answered Dec 21 '22 08:12

Zilong Wang


@WangSteven has a good solution.

In your case

[ngModel]="model?.name" (ngModelChange)="model ? model.name = $event : null"

should do as well.

?. is the elvis or safe-navigation operator which prevents evaluating the expression after the . when the expression before the . is null.

This happens when Angular tries to bind your model to the view before the model actually has a value.

like image 32
Günter Zöchbauer Avatar answered Dec 21 '22 07:12

Günter Zöchbauer