4

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

3 Answers 3

6

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>
Sign up to request clarification or add additional context in comments.

Comments

5

@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.

3 Comments

@Gunter Does elvis operator works with [(ngModel)] ? I am trying to do the same but it throws an error. The work around I did is [ngModel]="customer.guestType?.guest_type" (ngModelChange)="customer.guestType = $event"
@MateenKadwaikar thanks for the hint. That is not supposed to work. You are right, when ? is used the binding needs to be split.
@MateenKadwaikar the Elvis operator doesn't work on 2 way binding see github.com/angular/angular/issues/7697 hopefully it would get fixed in the future.
0

I've just had a similar issue and whilst it might be too late for you now here's something that worked for me if anyone else comes across this!

import { Class } from '../class';
class = <Class>{};

More info - Type Assertion

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.