0

Following this page, I'm finding that I can't execute an 'onclick' handler like the handler set up here:

function handler() {
  console.log(5);
}
<button onclick="handler()"></button>

This is the only module I use: <script type="module" src="../js/js_test.js"></script>. It's in the header.

This is the error I get:

enter image description here

It works when I have this in my module:

let button = document.querySelector('button');
button.onclick = handler;

Any ideas?

P.s. I can't access variables I write on my module on the console. I thought I once could do this. Don't know if that's helpful.

tonitone120
  • 1,920
  • 3
  • 8
  • 25
  • Are you sure the script file is loaded on that page ? and the script is added to the head of the page ? – Always Helping Sep 05 '20 at 01:22
  • Look at [Module Intro](https://javascript.info/modules-intro). You're missing some `export` and `import`. – Dominique Fortin Sep 05 '20 at 01:24
  • @AlwaysHelping yes – tonitone120 Sep 05 '20 at 01:24
  • @DominiqueFortin How do you mean if you wouldn't mind explaining? – tonitone120 Sep 05 '20 at 01:28
  • The handler function must be called before creating a button. Where are you putting the handler function? In the header or at the end of the html code? – Aks Jacoves Sep 05 '20 at 01:30
  • @AksJacoves In the header – tonitone120 Sep 05 '20 at 01:32
  • @tonitone120 Look at my answer below. – Dominique Fortin Sep 05 '20 at 01:36
  • I understand what happens, it's because you are using a module, and in modules you need to export the function and import it in the html code (Dominique answered this below) – Aks Jacoves Sep 05 '20 at 01:38
  • See [here](https://stackoverflow.com/a/59539045) for answer – CertainPerformance Sep 05 '20 at 01:59
  • 1
    (1) Inline handlers can only reference global variables (2) The top level of a module is not global. So, you'll need to find another way - preferably, by avoiding the inline handler; attach the listener via JS. Use your last code snippet instead - by assigning `.onclick = handler`, or with `button.addEventListener('click', handler)`, which will successfully bypass the scoping problems. – CertainPerformance Sep 05 '20 at 02:03
  • Sorry @CertainPerformance The link sometimes took me to a different post on that web-page. Am reading it now :) – tonitone120 Sep 05 '20 at 02:03
  • @CertainPerformance Thanks very much! Can I ask: in a normal script, what does it 'physically' mean to say variables declared at top-line become global? Do they get added to the global object (`window`) or another higher up object as a property? And is that how it's able to be referenced from other scripts? Would love to have globals nailed down – tonitone120 Sep 05 '20 at 02:15
  • 1
    Top-level variables become global *identifiers* (put into the topmost LexicalEnvironment that JS looks to when seeing what variable names are bound to what values), and as a result can be referenced by anything on the page. If the variable is declared with `var` or is a function declaration, it will also be automatically added as a property of the global object (`window`). Properties on the window are "global" in that they be referenced anywhere as well. It's not exactly the same thing as a global identifier, but it may as well be in the vast majority of cases. – CertainPerformance Sep 05 '20 at 02:22
  • @CertainPerformance Are all these global objects and global identifiers accessed in the same way as functions can see outside their scope? E.g. are our scripts sometimes like a function that can see all these non-visible lines of code outside of it? It's a bit abstract and would like to know more how it works if you had any reading recommendations. At the same time I'm happy to let it go if it wouldn't be of much use (I'm a beginnerish looking to get a job in front-end development) – tonitone120 Sep 05 '20 at 02:30
  • Yes, that's almost exactly it. Functions can see variables outside their blocks because the inner LexicalEnvironment lexically inherits from the outer LexicalEnvironment. When a variable name is not seen as defined in the inner LexicalEnvironment, the engine looks to the next outer environment, and so on, until the top environment is reached. This top environment contains identifier-value pairs that are not only explicitly declared variables on the top level, but also those which are properties of the global object. – CertainPerformance Sep 05 '20 at 02:34

3 Answers3

0

you can also use export and import. exporting your functions and importing it to another file

jayb
  • 9
  • 4
0

In js_test.js do

export function handler() {
  console.log(5);
}

In the html do

<html>
</head>
  <script type="module" src="../js/js_test.js"></script>

  <script type="module">
    import {handler} from '../js/js_test.js';

    document.onload = function(){
      document.getElementById('myButton').addListener("click", handler);
    };

  </script>
</head>
<body>
   <button id="myButton"></button>
</body>
</html>

EDIT per the suggestion of Aks Jacoves

An old way of doing module was

In js_test_old.js do

(function _module_x (global) {

  global.myNamespace = global.myNamespace || {};

  global.myNamespace.handler = _handler_;

  function _handler_ () {
    console.log(5);
  }
})(window);  // or })( (function(){return this;})() ); // this works for both Node.js and html

In the html do

<html>
</head>
  <script src="../js/js_test_old.js"></script>
</head>
<body>
   <button onclick="myNamespace.handler()"></button>
</body>
</html>
Dominique Fortin
  • 2,212
  • 15
  • 20
  • Thanks. Get an error 'Cannot use import statement outside a module' – tonitone120 Sep 05 '20 at 01:39
  • Add `type="module"` in second tag ` – Aks Jacoves Sep 05 '20 at 01:41
  • Still get the same error as in my post. Is it the case, for modules, that referencing the handler as the value to the attribute in `.html` file is only meant to work when the handler is present as 'inline' javascript (the content of a script tag in the `.html` file)? That seems annoying! I can get it to work when I turn my module into a regular script – tonitone120 Sep 05 '20 at 01:47
  • @tonitone120 Yes handler is only visible inside the script tag., but you can add it has a listener (ie. an event handler.) – Dominique Fortin Sep 05 '20 at 02:46
-1

Be sure to add a listener if the html element has finished loading

document.onload = function(){
   function handler(){
     console.log(5);
   }
}
jayb
  • 9
  • 4