32

I have a http request that gets this Json object from a nosql database:

let jsonBody = {
    birthday : 1997,
    firstname: 'foo',
    lastname:'bar'
}

Then I want to load this information into the Student model:

class Student{
    constructor(){

    }

    getFullname(){
        return this.lastname+' '+this.firstname
    }
    getApproxAge(){
        return 2018- this.birthday
    }
}

Normally, I would add this method to this class:

fromJson(json){
    this.studentId = json.studentId;
    this.birthday = json.birthday;
    this.firstname = json.firstname;
    this.lastname = json.lastname;
}

I would use it as follow:

let student = new Student()
student.fromJson(jsonBody)
console.log(student.getFullname())
console.log(student.getApproxAge())

This works fine but my problem is I have: 100 proprieties in reality. Will I have to write all proprities one by one in the fromJson method?

And also, if a propriety name has change, let's say: lastname became LastName, I will have to fix it?

Is there a simpler way to just assign these values to the object student dynamically but keep all of its methods??

Something like this:

fromJson(json){
    this = Object.assign(this, json) //THIS IS NOT WORKING
}
TSR
  • 17,242
  • 27
  • 93
  • 197
  • You *could* do something like your last snippet but it would probably be better if you manually do `this.lastname = data.lastname` and so on for each property. This will protect you if in the future the data you get does turn into `LastName`, since you only need to modify the initialisation code. Related, you probably want to initialise by data, so you can pass the server response in the constructor `new Student(responseData)` and do all the property setting there. – VLAZ Sep 13 '18 at 13:53
  • 1
    Possible duplicate of [convert javascript plain object into model class instance](https://stackoverflow.com/questions/33778934/convert-javascript-plain-object-into-model-class-instance) – HugoTeixeira Sep 13 '18 at 14:00
  • By the way, js has real getters do you could do `get fullname() { return this.firstname + " " + this.lastname; }` and then `console.log(student.fullname)` – Jonas Wilms Sep 13 '18 at 14:14
  • @TSR You might want to use Typescript . it is a superset of javascript does allows you to check the types, in other it will alert you if one propriety is missing or incorrect. – TSR Mar 14 '19 at 19:06

2 Answers2

68

Just assign to an instance:

 static from(json){
   return Object.assign(new Student(), json);
 }

So you can do:

 const student = Student.from({ name: "whatever" });

Or make it an instance method and leave away the assignemnt:

 applyData(json) {
   Object.assign(this, json);
 }

So you can:

 const student = new Student;
 student.applyData({ name: "whatever" });

It could also be part of the constructor:

 constructor(options = {}) {
  Object.assign(this, options);
 }

Then you could do:

 const student = new Student({ name: "whatever" });

And also, if a property name has changed, let's say: lastname became LastName, I will have to fix it?

Yes you will have to fix that.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
7

There is no way in javascript to deserialize json into classes. So I wrote a library ts-serializable that solves this problem.

import { jsonProperty, Serializable } from "ts-serializable";

export class User extends Serializable {

    @jsonProperty(String)
    public firstName: string = ''; // default value necessarily

    @jsonProperty(String, void 0)
    public lastName?: string = void 0; // default value necessarily

    @jsonProperty(Date)
    public birthdate: Date = new Date(); // default value necessarily

    public getFullName(): string {
        return [
            this.firstName,
            this.lastName
        ].join(' ');
    }

    public getAge(): number {
        return new Date().getFullYear() - this.birthdate.getFullYear();
    }
}

const user: User = new User().fromJSON(json);
user.getFullName(); // work fine and return string
user.getAge(); // work fine and return number

// or
const user: User = User.fromJSON(json);
user.getFullName(); // work fine and return string
user.getAge(); // work fine and return number

The library also checks types during deserialization.