Reputation: 11642
I am using decorators in typescript/angular in the following way
export function Field({source}){
return (target, property) => {
// Some code here
}
}
Then I want to use it this way
export class MyClass {
constructor(private myService: MyService) {}
@Field({source: () => this.myFn()})
myProp: string;
private myFn() {
// another code
return this.myService.get()
}
}
Obviously the context is wrong and "this" does not refer to the instance of MyClass. What is the best way to link this context with the instance of MyClass?
Upvotes: 1
Views: 1393
Reputation: 20494
You can get access to instances in decorators with roundabout methods depending on what you're trying to do. In the example below the function passed to the decorator is called every time the property is set.
The decorator will work for both properties and fields. If a field is being decorated then the prototype of the target is modified and the field is converted into a property with a hidden backing variable to store the property value.
Note how this does not use arrow functions to define the getter and setter. This is how it the instance can be retrieve at the time the property/field is getting set. Personally, I use arrow functions so much I forget something like this was even possible until I tried it out.
function Field(srcFunc) {
return function (target: any, propertyKey: string, descriptor?: PropertyDescriptor) {
if (descriptor == null) {
const backingKey = `__${propertyKey}`;
Object.defineProperty(target, backingKey, { enumerable: false, writable: true });
Object.defineProperty(target, propertyKey, {
configurable: true,
enumerable: true,
get: function() {
return this[backingKey];
},
set: function(value) {
this[backingKey] = value;
srcFunc.call(this);
}
});
}
else {
const setOriginal = descriptor.set;
descriptor.set = function(value) {
setOriginal.call(this, value);
srcFunc.call(this);
}
}
}
}
export class MyClass {
@Field(MyClass.prototype.myFn)
myProp: string;
private myFn() {
// another code
}
}
Upvotes: 1