Brandon Brandon - 2 months ago 29
TypeScript Question

Angular2 FormBuilder and nested object property returns undefined

I'm just getting my feet wet with TypeScript and Angular2. I'm working with an API that has a nested object structure. I would like my model to mirror the resource from the API. The model/resource, "Inquiry", as defined in TypeScript:

// inquiry.ts
export class Inquiry {
name: {
first: string,
last: string
};
email: string;
phone: string;
question: string;
}


My form component is as such:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { InquireService } from './inquire.service';
import { Inquiry } from './inquiry';

@Component({
selector: 'inquire-form',
templateUrl: './inquire-form.component.html'
})
export class InquireFormComponent implements OnInit {
inquiryForm: FormGroup;
inquiry = new Inquiry;

constructor(
private formBuilder: FormBuilder,
private inquireService: InquireService) {}

ngOnInit(): void {
this.buildForm();
}

buildForm(): void {
this.inquiryForm = this.formBuilder.group({
'firstName': [
this.inquiry.name.first, [
Validators.required,
Validators.minLength(2),
Validators.maxLength(50)
]
], ...
}
}


The error I get when I hit my route is:

Error: Uncaught (in promise): TypeError: Cannot read property 'first' of undefined


When I log
this.inquiry.name
it is indeed
undefined
, but I'm not understanding why. What am I doing wrong?

Answer

The problem is that none of your properties on the Inquiry object are initialized so they're all the default value undefined. And since the one that matters name isn't initialized, attempts to access any of its properties (first or last) will fail.

Either set it in a constructor:

constructor() {
    this.name = {} as any; // too lazy to give first/last properties
}

or initialize it in the declaration:

class Inquiry {
    name = {} as {
        first: string,
        last: string
    };
    email: string;
    phone: string;
    question: string;
}