https://stackoverflow.com/a/41300128
↑ completely based on this code
var validator = {
get(target, key) {
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], validator)
} else {
return target[key];
}
},
set (target, key, value) {
console.log(target);
console.log(key); // salary
console.log(value); // foo
// ⭐ Is it possible to get "inner" here?
return true
}
}
var person = {
firstName: "alfred",
lastName: "john",
inner: {
salary: 8250,
Proffesion: ".NET Developer"
}
}
var proxy = new Proxy(person, validator)
proxy.inner.salary = 'foo'
As I wrote in code with star emoji, is it possible to get parent property name of nested object in set method of Proxy object?
And any alternative solutions you have?
Yes, it is possible by creating new proxy handlers where each keeps the full path which was used to access the property. This is essentially a recursive technique to keep data during recursive calls:
const makeHandler = (path = []) => ({
get(target, key) {
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], makeHandler(path.concat(key)))
} else {
return target[key];
}
},
set (target, key, value) {
// ⭐ it is possible to get "inner" here
console.log("path", path);
return Reflect.set(...arguments);
}
});
var person = {
firstName: "alfred",
lastName: "john",
inner: {
salary: 8250,
Proffesion: ".NET Developer"
}
}
var proxy = new Proxy(person, makeHandler());
proxy.inner.salary = 'foo';
It will also work if you separate the access and setting to multiple expressions:
const makeHandler = (path = []) => ({
get(target, key) {
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], makeHandler(path.concat(key)))
} else {
return target[key];
}
},
set (target, key, value) {
// ⭐ it is possible to get "inner" here
console.log("path", path);
return Reflect.set(...arguments);
}
});
var person = {
firstName: "alfred",
lastName: "john",
inner: {
salary: 8250,
Proffesion: ".NET Developer"
}
}
var proxy = new Proxy(person, makeHandler());
const x = proxy.inner;
proxy.firstName;
x.salary = "foo";
Even if you have circular dependencies:
const makeHandler = (path = []) => ({
get(target, key) {
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], makeHandler(path.concat(key)))
} else {
return target[key];
}
},
set (target, key, value) {
// ⭐ it is possible to get "inner" here
console.log("path", path);
return Reflect.set(...arguments);
}
});
const foo = { bar: 1 };
foo.foo = foo; //circular dependency
var proxy = new Proxy(foo, makeHandler());
proxy.foo.foo.foo.foo.bar = 2;
console.log("after setting `bar`", foo);
Or otherwise have multiple paths to a property, this proxy will keep the path that was used to access such property:
const makeHandler = (path = []) => ({
get(target, key) {
if (typeof target[key] === 'object' && target[key] !== null) {
return new Proxy(target[key], makeHandler(path.concat(key)))
} else {
return target[key];
}
},
set (target, key, value) {
// ⭐ it is possible to get "inner" here
console.log("path", path);
return Reflect.set(...arguments);
}
});
const person = {
firstName: "alfred",
lastName: "john",
inner: {
salary: 8250,
Proffesion: ".NET Developer"
}
}
//same object at multiple paths
const obj = {
firstLevel: person,
one: {
two: {
three: person
}
},
a: {
b: {
c: person
}
}
};
var proxy = new Proxy(obj, makeHandler());
proxy.firstLevel.inner.salary = 1000;
console.log("after setting `proxy.firstLevel.inner.salary`:", person);
proxy.one.two.three.inner.salary = 2000;
console.log("after setting `proxy.one.two.three.inner.salary`:", person);
proxy.a.b.c.inner.salary = 3000;
console.log("after setting `proxy.a.b.c.inner.salary`:", person);
.as-console-wrapper { max-height: 100% !important; }