Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a nested object within model? (angular2/typescript)

I'm playing around with Angular2, and was hoping someone could offer some advice on how to achieve this;

For example, if my model currently looks like this for an employee:

export class Employee {
    constructor(
        public firstName: string,
        public lastName: string,
        public email: string,
        public days: string,
        public hours: string, 
    ){}
}

and I want to to place days/hour into their own object, how could that be achieved?

(i.e like..)

public availability: {
        public days: string,
        public hours: string
},

and then would the http get request stay the same like below?

getEmployees() {
      return this.http.get('...')
             .map((response: Response) => {
                 const data = response.json().obj;
                 let objs: any[] = [];

                 for(let i = 0; i < data.length; i++) {
                     let employee = new Employee(
                     data[i].firstName,
                     data[i].lastName, 
                     data[i].email, 
                     data[i].availability.days,
                     data[i].availability.hours
                     );

                     objs.push(employee)
                 }
                 return objs
             })
          }

Just to clarify, I would like my get request to return something like;

var obj = {
    firstName: "test",
    lastName: "test",
    email: "test",
    availability: {
      days: "test",
      hours: "test"
    }
  }

Hope someone can help out! I'm tried to look around, but haven't come across anything that can help.

like image 786
confusedandenthused Avatar asked Nov 16 '16 13:11

confusedandenthused


3 Answers

Something like this

export class Employee {
    constructor(
        public firstName: string,
        public lastName: string,
        public email: string,
        public availability: Availability // refer to type Availability  below
    ){}
}

export class Availability {
    constructor(
        public days: string,
        public hours: string
    ){}
}

Http get request should stay the same, then change on how you create new instance of employee

let employee = new Employee(
    data[i].firstName,
    data[i].lastName,
    data[i].email,
    new Availability(
          data[i].availability.days,
          data[i].availability.hours
    )
);
like image 107
Michael Avatar answered Nov 04 '22 08:11

Michael


Personally I did ( for Ionic project ) something like

export class Availability {
    days: string  = "";
    hours: string = "";
}

export class Employee {
    firstName: string = "";
    lastName:  string = "";
    email:     string = "";

    availability = new Availability()
}

So if I use these models in a <form> I receive an empty structure of this Employee class.

It also work when I declare variables like employeeObservable : Observable<Employee[]>; when I query a firebase DB for example ...

like image 22
Ricky Levi Avatar answered Nov 04 '22 10:11

Ricky Levi


For anyone showing up to this a couple years later, there's a helpful library that can help with this called class-transformer.

Using this library has been the easiest: https://github.com/typestack/class-transformer

import { Type } from 'class-transformer';

export class Employee {
    firstName: string;
    email: string;
    days: string;
    hours: string;

    @Type(() => Availability)
    availablity: Availablity

    constructor(args: Employee) {
      Object.assign(this, args);
    }
}

export class Availability {
    days: string;
    hours: string;

    constructor(args: Availability) {
      Object.assign(this, args);
    }
}

A few things changed:

  1. The use of the @Type decorator comes from the class-transformer module. This allows you to transform nested objects. Here is the documentation: https://github.com/typestack/class-transformer#working-with-nested-objects
  2. We've added a constructor which allows you to create instances of these Classes and pass through attributes to them of their own respective types. Take a look at this post Converting httpClient answer to model objects [Angular 6] as it shines more light onto whats happening here.

Then within your service this is how your code changes:

import { plainToClass } from 'class-transformer';
import { Employee } from './Employee'

getEmployees() {
  return this.http.get('...')
    .map((response: Response) => plainToClass(Employee, response.json().obj as Employee[]))

plainToClass will take the raw JSON response and transform it into instances of your Employee Class. If you console.log out the result of getEmployees() you will see that it returns an Array of Employees that each have an attribute called availability of type Availability.

like image 2
jetset Avatar answered Nov 04 '22 08:11

jetset