8

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.

3 Answers 3

20

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

5 Comments

Hi, I'm getting errors using this example - Cannot find name 'Availability'. is what appears in the service, and in the class file - ';' expected. I think the export class Availability won't be visible inside the Employee class unless you import it?
@confusedandenthused yeah sorry, the Availability class should have its constructor, I have fixed it, then import Availability class in the Employee class and in your service.
Thanks - that got it working! Also worth noting that you have to import the new class into the component to get it to work.
what if the model has one hundred property? you can't do it like this.
You need to define interfaces instead of classes to work properly.
3

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

Comments

2

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.

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.