Richard Friend
Richard Friend

Reputation: 16018

Read properties of component from within PropertyDecorator

When applying @Input() decorators to my component properties, then chaining together with my custom decorator.

I don't seem to be able to read/set any of my public properties - even though they bind correctly.

For example

  @Input()
  @Language('global.pw.current')
  public existingPasswordLabel: string;

Then in my language decorator

export function Language(keyId: string): PropertyDecorator {
  return (target: any, key: string) => {
    setTimeout(()=>{
      console.log(target[key]); //This is never set but is on screen
      // in fact none of my public component properties are on the target
    },1000); //Plenty of delay to make sure binding has happened
  };
}

How to read/write my component properties at this point.

Upvotes: 0

Views: 280

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249696

The target object is not an instance of your class, it is the class itself, and since the property you are trying to set is on an instance of a the class, target[key] will never be set to anything (It is in essence Class[key])

You can try to overwrite the field to be a property so you have access to when the property is get/set

export function Language(keyId: string): PropertyDecorator & MethodDecorator {
    return (target: any, key: string, desc?: PropertyDescriptor) => {
        desc = desc || {
            get: function () {
                return this["_" + key];
            },
            configurable: true,
            enumerable: true
        };

        let baseSetter = desc.set || function (value) {
            this["_" + key] = value;
        };

        desc.set = function (value) {
            console.log(`Value of ${key} is ${value} with ${keyId}`);
            baseSetter.call(this, value);
        };
        // We return the property descriptor which will be used to define the property using Object.defineProperty in the __decorate helper
        return desc; 
    };
}
class ChildComponent {
    @Language('global.pw.current')
    @Input()
    public existingPasswordLabel: string;
    // Works with properties as well 
    private _title: string;
    @Language('global.title')
    @Input()
    public get title(): string {
        return this._title;
    }
    public set title(value: string) {
        this._title = value;
    }
}

Note: I did not test with the @Input decorator added, but it should work.

Edit: Tested with the @Input decorator, and everything works as expected. Also I updated code to work with both fields and properties.

Upvotes: 2

Related Questions