I am trying to bind to a property of a nested object with [(ngModel)], but the problem is that the "path" to property is dynamically set.
Let's say we have three classes like so:
class A {
p1: C
constructor() {
p1 = new C("A")
}
}
class B {
p2: C
constructor() {
p2 = new C("B")
}
}
class C {
constructor(public id: string){}
}
reusable.component.html like this:
<input [(ngModel)]="data[propName]">
reusable.component.ts like this:
@Component({
selector: "app-reusable[data][nestedProperty]",
templateUrl: "./reusable.component.html"
})
export class ReusableComponent<T> {
@Input()
nestedProperty!: string
@Input()
data!: T
}
and app.component.html like so:
<app-reusable [data]="d1" [nestedProperty]="s1"></app-reusable>
<app-reusable [data]="d2" [nestedProperty]="s2"></app-reusable>
and app.component.ts like so:
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
d1 = new A()
d2 = new B()
s1 = "p1.id"
s2 = "p2.id"
}
my logic for this kind of approach was that d1.p1
gets the same value as d1["p1"]
, but i found out that d1["p1.id"]
does't get the same value as d1.p1.id
Is there any kind of workaround that would enable me to fetch a nested object value using only string path to the nested object?
My workaround was to create property d1["p1.id"]
inside the constructor and assign it d1.p1.id
value like so:
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
d1 = new A()
d2 = new B()
s1 = "p1.id"
s2 = "p2.id"
constructor() {
this.d1[s1] = this.d1.p1.id
this.d2[s2] = this.d2.p2.id
}
}
If you know the path to get the property You can use eval
to evaluate the expression to access it:
The eval() function evaluates JavaScript code represented as a string
If you have an object as
var myObject = {
innerObject: {
nestedProperty: 'The value'
}
};
You can get the string 'The value' doing
var nestedValue = eval("myObject.innerObject.nestedProperty");
// Here nestedValue has the value 'The value'
Note that the use of eval can be dangerous because it will execute any kind of string as it is a code, so a better way to solve the problem in this case is to use the Function
as explained here
function extractProperty(path) {
return Function('"use strict";return (' + path + ')')();
}
and use it as follow for the previous example:
var nestedValue = extractProperty("myObject.innerObject.nestedProperty");
This is a standard javascript code, but you can adapt it to your typescript needs.