PsyGik
PsyGik

Reputation: 3675

Map JSON to TS Class. If property is an obj and not found in JSON, class should have empty obbj

I am unable to come up with a suitable title to the problem I am facing. So I will try to explain the problem as detailed as possible.

I have a class defined say Model.ts

export class Model{
    a:ObjA;
    b:ObjB;
    c:ObjC;
    d:string;
    e:boolean;
    constructor(){
        this.a = new ObjA();
        this.b = new ObjB();
        this.c = new ObjC();    
    }
}

The sub classes are kept simple for the question ObjA.ts

export class ObjA{
    propA:string;
    propB:ObjD;
    constructor(){
        this.propB = new ObjD();
    }
}

ObjB.ts

export class ObjB{
    propA:string;
    propB:number;
}

ObjC.ts

export class ObjC{
    propA:string;
    propB:number;
}

Now from a service, I get the following JSON

{a:{propA:"some val"},c:{propB:12},d:"blah"}

What I want is to be able to assign the JSON to class Model so that i get this

{a:{propA:"some val",propB:{}},b:{},c:{propB:12},d:"blah"}

Using Object.assign(new Model(),json) gives me

{a:{propA:"some val"},c:{propB:12},d:"blah"}

Note the absense of b here. And also a is missing propB

So my question is, How do I map the json such that if any property, which is an object, is missing in the json, it will just create an empty object? (I am open to using loadash and such utils)

P.S: The use case here is I am writing an Angular2 app in which the properties are entered using a form. If I use elvis operator in html (obj?.prop), because the obj doesn't have that property, the value for that property is never set. If i don't use elvis, then the age old undefined is thrown.

Sample form:

...
    <input [(ngModel)]="model.a.propA"/>
    <input [(ngModel)]="model.a.propB"/>
    <input [(ngModel)]="model.b.propA"/>
    <input [(ngModel)]="model.b.propB"/>
    .
    .
    .
...

Corresponding *.ts component

class Component implements OnInit{
  ....
  model:Model = new Model();
  ngOnInit(){
    getData().subscribe(res=>Object.assign(model,res));
  }
}

Upvotes: 4

Views: 662

Answers (1)

Frank Modica
Frank Modica

Reputation: 10516

You could use Object.assign combined with a default object which you create. You'll end up merging the properties of both objects, with the JSON overriding the defaults:

let defaultObj  = { a: "default value a", b: "default value b" };

let json = { a: "json value a" };

let model = Object.assign({}, defaultObj, json);

Result:

{a: "json value a", b: "default value b"}

However, this is only a shallow copy of the properties from defaultObj and json. Since some of your properties are objects, you may want to deep clone the result of Object.assign so you aren't sharing the same object among various bindings in your view.

Edit: As mentioned in the comments, libraries like underscore provide functions like _.merge which would both merge and deep clone.

Upvotes: 3

Related Questions