8

I have some HTML with a button whose onclick event triggers a JavaScript function.

I need to achieve the same behavior when the JavaScript function is an ES6 module function.

I have a simple example:

<head>
  <meta charset="utf-8">
  <script src="./js1.js"></script>
  <script type="module" src="./js2.js"></script>
  <script type="module">
    import { Es6Module3 } from "./js3.js";
    document.querySelector('#myFunction3').addEventListener('click', Es6Module3.myFunction3);
  </script>
</head>

<body>
  <button onclick="myFunction1(1)">button1</button>
  <button onclick="Es6Module2.myFunction2(2)">button2</button>
  <button type="button" id="myFunction3">button3</button>
</body>

It's also reproduced at https://jsfiddle.net/avnerm/jho6qgLu/18/

When clicking button1, the function myFunction1 in js1.js is called, and the value that is passed in is printed properly into the console. good!

But when clicking button2 I get a message:

ReferenceError: Es6Module is not defined

At some point I was able to trigger a module function (the use case of button3) by setting an event listener, but it's not working now and I don't know how to pass a parameter into the function in this implementation.

In my case, I need to be able to pass in a parameter.

How can I call a ES6 module function from the onclick attribute, and pass a parameter to it?


EDIT:
@CertainPerformance, My original html code involves jinja2, which spans the code 3 times (3 groups with ids: 1, 2, 3)

I used your pattern, and it created 3 buttons (button1, button2, button3) with 3 event listeners. When I click on each button I can see in the log the appropriate group id.

This works for me perfectly!

I just wanted to confirm that this is the way to deal with html, jinja2, and es6.

Thanks!

class Es6Module2 {
    static myFunction2 = function(val) {
        console.log('BEG myFunction2');
        console.log('val'); 
        console.log(val); 
    };
};

export { Es6Module2 };
{% block content %}

<div class="admin-view-groups">
    {% for group in groups %}
        <button id="button{{group.id}}">Download Group</button>
        <script type="module">
         import { Es6Module2 } from './Es6Module2.js';
         document.querySelector('#button{{group.id}}').addEventListener('click', () => {
             Es6Module2.myFunction2({{ group.id }});
         });
        </script>
    {% endfor %}
</div>

{% endblock %}
Avner Moshkovitz
  • 1,138
  • 1
  • 18
  • 35

1 Answers1

15

The only way to do it would be to assign the imported module function to the window object so that it can be referenced by the inline handler:

  <script type="module">
    import { Es6Module2 } from "./js2.js";
    window.Es6Module2 = Es6Module2;
  </script>

But that defeats the purpose of modules.

Regardless, inline handlers should never, ever be used. They have way too many problems, including this one (requiring the function to be called to be in the global scope). Best to avoid them and use addEventListener instead, to add the listener properly.

If you want to add a listener which calls a function with a parameter, then just call the function with the parameter in the listener:

import { fn } from './script.js';
document.querySelector('button').addEventListener('click', () => {
  fn('foo');
});
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Can you show how to use the addEventListener and pass in param from the html to the javascript function? I was able to hook up the button3 to the function myFunction3, but it's not working now and I don't know what is wrong. Also I couldn't pass a parameter using this approach. Thanks – Avner Moshkovitz May 27 '20 at 01:19