Reputation: 3675
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 alsoa
is missingpropB
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
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