简体   繁体   中英

How can I import module exported functions into the global scope for HTML onclick=“” event-handlers?

A simple HTML webpage using SystemJS 0.21 that's loading a JavaScript module compiled from TypeScript. The HTML web-page has an onclick="" -style event-handler that calls a function declared in a module file:

tsconfig.json

{
    "compilerOptions": {
        "module": "system",
        "moduleResolution": "node"
    }
}

Page.ts

export function onButtonClick( e: Event, btn: HTMLButtonElement ): boolean {

    console.log( 'clicked!' );
    return true;
}

I'm using SystemJS in a HTML page in a website (not an SPA) like so:

system.config.js

System.config( {

    map: { /* ... */ },

    packages: {
        '/scripts/': { defaultExtension: 'js' }
    }

} );

System.import( '/scripts/Page' );

Page.html

<html>
<head>
    <script src="/scripts/system.src.js"></script>
    <script src="/scripts/system.config.js"></script>
</head>
<body>

    <button onclick="onButtonClick( event, this )">Click me and check the browser console</button>

</body>
</html>

This doesn't work because the onButtonClick function is defined in Page.js as a function within the module, which means it is not imported as a property into the global ( Window ) object in consuming scripts. So I get this output in my console window:

Uncaught ReferenceError : onButtonClick is not defined at HTMLButtonElement.onclick (Page.html:8)

So how can I get my <button onclick="onButtonClick( event, this )" to use the function onButtonClick in Page.ts / Page.js ?

I developed a workaround solution for now:

  1. Extend the global Window object interface in the TypeScript module to add the new global functions.
  2. Assign those declared function properties on window within the module's "top-level" function.

This isn't the same thing as having SystemJS importing a module into the window object (which is what I originally wanted) and this approach also requires me to modify the module I'm importing, but it works for now.

Like so:

Page.ts

declare global {
    declare interface Window {
        onButtonClick( e: Event, btn: HTMLButtonElement ): boolean;
    }
}

function onButtonClick( e: Event, btn: HTMLButtonElement ): boolean {

    console.log( 'clicked!' );
    return true;
}

window.onButtonClick = onButtonClick;

The onButtonClick function no-longer needs to be exported. And this can be made even more succinct by just assigning the function directly:

Page.ts

declare global {
    declare interface Window {
        onButtonClick( e: Event, btn: HTMLButtonElement ): boolean;
    }
}

window.onButtonClick = onButtonClick( e: Event, btn: HTMLButtonElement ): boolean {

    console.log( 'clicked!' );
    return true;
};

Because the Page.ts / Page.js module is loaded asynchronously it does mean that when Page.html loads the onclick="" attributes won't work until the module is loaded - but assuming that happens quickly after the page loads there won't be any user-experience issues.

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