wonder
wonder

Reputation: 75

Getting error when trying to subscribe to function in ngOnInit

I am getting error "Cannot read property 'name' of undefined" I have a simple api that returns a Vehicle, which has these fields

    public int Id {get ;set;}
    public int ModelId { get; set; }

    public KeyValuePairResource Model { get; set; }
    public KeyValuePairResource Make { get; set; }
    public bool IsRegistered { get; set; }

    public Contact ContactInformation { get; set; }

    public DateTime LastUpdate {get; set;}
    public ICollection<KeyValuePairResource> Features  { get; set; }`

Now, In the angular front end, I have a simple get method that calls this api endpoint

getVehicle(id) {
   return this.http.get('/api/vehicles/'+ id);


}

in my angular component onInit function i am doing

ngOnInit() {

this.makes = this.vehicleService.getMakes();
this.features = this.vehicleService.getFeatures();
// this.vehicle is defined as any 
this.vehicleService.getVehicle(this.vehicle.id)
.subscribe(res=> { this.vehicle = res ;});

}

and finally the code where the program fails seems to be in the HTML

<div class="form-group"><label for="ContactName">Name</label>
        <input id= "ContactName" required #name="ngModel" type="text" class="form-control" [(ngModel)] = "vehicle.ContactInformation.name " name = "name"></div>
    <div class="alert alert-danger" *ngIf="!name.valid && name.touched">Please enter Name</div>

I have seen similar problems on stack, but none of them have actually solved my problem. I know that the function is asynchronous and the webpage tries to load it before the async function returns completely. But i have other parts in the code where i try to access things like in

<div *ngFor="let f of features"class="checkbox">
<label for="feature{{f.id}}" (change) = "onFeatureToggle(f.id , $event)">
    <input type="checkbox" id="feature{{f.id}}">{{f.name}}
</label>

and that doesn't seem to crash. I am really confused. I think i have given what is necessary for this problem, but please tell me if i need to provide more code. The worst part is, i actually got it to work by accident, and the code in onInit didn't look any different.

Upvotes: 1

Views: 260

Answers (1)

Poul Kruijt
Poul Kruijt

Reputation: 71911

In your component the expression vehicle.ContactInformation.name is not defined, because ContactInformation is undefined. This will cause an error in the template.

Because you are using ngModel with two way binding, you cannot use vehicle.ContactInformation?.name. You should try to first check if it exists with an *ngIf:

<input *ngIf="vehicle.ContactInformation" 
       id="ContactName" required #name="ngModel"
       type="text" class="form-control"
       [(ngModel)]="vehicle.ContactInformation.name" name="name">

Or you can not use two way binding and split it up:

<input
       id="ContactName" required #name="ngModel"
       type="text" class="form-control"
       [ngModel]="vehicle.ContactInformation?.name" 
       (ngModelChange)="vehicle.ContactInformation ? vehicle.ContactInformation.name = $event : null"
       name="name">

The reason it works with your *ngFor loop, is because the *ngFor checks if the passed array is defined, if it's not, it doesn't loop.

You can also try to initialize your object beforehand:

vehicle = {
  id: this.route.snapshot.params.id,
  features: [],
  contactInformation: {}
};

But I think the issue you are having, is that it's contactInformation and not ContactInformation. The rest of your code seems to be using lowercase like features and id, I don't see why just ContactInformation is with a capital

Upvotes: 3

Related Questions