简体   繁体   中英

How can Typescript decorators be used for html labels?

I am having a difficult time understanding how to use Typescript decorators . I have this code:

class Address {
    private street: string;
    private city: string;
    private state: string;
    private zipCode: string;

    @displayName("Street")
    get streetHtml() { return this.street; }

    @displayName("City")
    get cityHtml() { return this.city; }

    @displayName("State")
    get stateHtml()  { return this.state; }

    @displayName("Zip Code")
    get zipCodeHtml() { return this.zipCode; }

    public static map(input: any) {
        let address = new Address();

        address.street = input.street;
        address.city = input.city;
        address.state = input.state;
        address.zipCode = input.zipCode;

        return address;
    }
}

function displayName(name: string) {

    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        let label: HTMLLabelElement = document.createElement('label');

        label.innerHTML = name;

        return label;
    };
}

var address = Address.map({ street: "123 My St", city: "Boise", state: "ID", zipCode: "83709" })

console.log(address.cityHtml);

However, the only thing this is doing is returning "Boise". How do I get at the decorator stuff? I did enable "experimentalDecorators": true , in my tsconfig .

As commented by @JohnWhite, the getters in your class return a string (that's being inferred by the compiler from the return type), but the decorator you're asking for changes that to return a HTMLLabelElement .
This might create difficulties for you in compile time, or end up in runtime errors.

With that being said, to answer your question:
What you return in the decorator isn't the returned value of the accessor, as the docs say :

If the accessor decorator returns a value, it will be used as the Property Descriptor for the member

What you need to do is to change the "Property Descriptor" so that it returns your desired value:

function displayName(name: string) {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        descriptor.get = () => {
            let label: HTMLLabelElement = document.createElement('label');
            label.innerHTML = name;

            return label;
        }
    };
}

( code in playground )


Edit

After posting my answer I noticed that you want to get:

<label>Boise</label>

But how you tried to implement it (and my answer) returns:

<label>City</label>

In order to get the desired result we need to change my code a bit:

function displayName(name: string) {
    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        descriptor.get = function() {
            let label: HTMLLabelElement = document.createElement('label');
            label.innerHTML = this[name.toLowerCase()];

            return label;
        }
    };
}

( code in playground )

Where the changes are:

  1. The return function is now a regular anonymous function instead of an arrow function so that the this will point to the class instance instead of the window.
  2. The label inner html is now this[name.toLowerCase()] instead of name

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM