matt forsythe
matt forsythe

Reputation: 3922

How to instantiate TypeScript domain objects from JSON that is returned from the server in an Angular application

I am having trouble with what I have to believe is a fairly common situation in Angular / Typescript / JavaScript in general. I have a simple class with some fields and some methods.

class Rectangle {
  width: number;
  height: number;

  area(): number {
    return this.width * this.height;
  }
}

I then have a service with the following method that retrieves these things from my server:

class RectangleService {

...  // blah blah blah

  getRectangle (id: number): Observable<Rectangle> {
    // no error handling needed - nothing ever goes wrong with web services...  :) 
    return this.http.get<Rectangle> ('http://myserver.com:8080/rectangle/' + id);  
  }
}

And of course, my web service returns something like

{width: 10, height:15}

But then once I get the thing back, I can't call area() on it because (I am guessing) we have a bare JavaScript associative array masquerading as a Rectangle. Which makes sense to some degree I suppose - this isn't Java where object creation is locked down by constructors. But what is the accepted way to get that data from JSON returned by the web service into a proper Rectangle that has the methods available?

Do I have to manually build a constructor to do this? This obviously wouldn't be tedious in this case, but in the case where there are several nested objects, it seems like it could get out of hand quickly.

I have seen some "roll-your-own" solutions (and some are very good), but this would seem to be a very common scenario in Angular, so I find it strange that there is no commonly accepted practice or library to do this. Am I doing something wrong here?

Upvotes: 3

Views: 693

Answers (1)

DeborahK
DeborahK

Reputation: 60548

The server just returns data formed with properties from the defined object. It doesn't actually create an instance of the object.

Try something like this:

return this.http.get<Rectangle> ('http://myserver.com:8080/rectangle/' + id)
               .map(res => Object.assign(new Rectangle(), res));

This should create the object and then copy any of the retrieved properties into it.

Here is some sample code I used on the TypeScript playground (https://www.typescriptlang.org/play/):

class Hospital {
    hospital: string;
    doctors: Doctors[];
}
class Doctors {
    id: number;
    ward: string;
}

class Test {
    hospitals: Hospital[] = [];
    hospitals2: Hospital[];
    constructor() {
        this.hospitals[7] = {
            hospital: "New York Hospital",
            doctors: [{
                id: 1269,
                ward: "test"
            }]
        };
        this.hospitals2 = Object.assign(new Hospital(), this.hospitals);
    }

    data() {
        return JSON.stringify(this.hospitals) + '<br>' +
               JSON.stringify(this.hospitals2);
    }
}

let tester = new Test();

let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
    alert(tester.data());
}

document.body.appendChild(button);

Upvotes: 2

Related Questions