Brandon Taylor
Brandon Taylor

Reputation: 34593

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?

Upvotes: 0

Views: 1626

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134581

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;
}

or if you want to explicitly keep the type in the declaration and not rely on type inference:

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

Upvotes: 2

Related Questions