Manish Deshpande
Manish Deshpande

Reputation: 63

Javascript modules import fails

I'm trying enter code here in to execute an imported module from a HTML page. I get to see that it's partially getting executed. I need help. My code files are test.html, main.js and say.js. These files are produced below in the same order.

test.html:

<html>
 <head>
     <script type="module" src="./main.js"></script>
 </head>
 <body onload="sayHi('Manish')">
 </body>
</html>

main.js:

import { sayHi } from './say.js';
sayHi('MK');

say.js:

export function sayHi(user) {
alert('Hello, { $user }');}

This code partially executes

Then after this partial execution, it gives an error

Uncaught ReferenceError: sayHi is not defined

at onload (test.html:7)

The picture of the error is as shown below:

This is the error that says sayHi function is not recognized. Why?

What am I doing wrong here?

Upvotes: 3

Views: 4567

Answers (3)

Manish Deshpande
Manish Deshpande

Reputation: 63

Basically my objective was to pass some parameter from the HTML script to the main.js file. I have got the required after both of you have given me hints, especially Vikas Saini. The suggestion of adding an event listener in the main.js file helped a lot. Thanks much. I'm posting the corrected and the latest code files for the benefit of ES6 beginners like me.

The test.html file contents

<html>
<head>
    <script type="module" src="./main.js"></script>
</head>
<body>
    <input type="text" id="btn-say-hi"label="fill here" placeholder="Fill in here and click"/>
</body>
</html>

The main.js file contents

import { sayHi } from './say.js';
document.getElementById("btn-say-hi").addEventListener("click", function() {
    sayHi(this.value);
});

The say.js file contents

export function sayHi(user) { alert(`Hello, ${user}`); }

Kindly note: All these files are in the same directory/folder. I could change the text item value and could get the required execution based on my inputs.

Thanks much to T.J. Crowder and a special thanks to Vikas Saini for the code snippet pertaining to adding the event listener. That was a golden suggestion.

Thanks much guys. Regards Manish.

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1073968

One of the great things about modules is that top level declarations, etc., in them don't create globals. One of the bad things about onxyz-attribute-style event handlers is that the functions you call with them have to be globals. Your sayHi isn't a global, so onload="sayHi('Manish')" fails because it doesn't have access to sayHi.

Which is a good thing.

Instead, just call the function from main.js:

import { sayHi } from './say.js';
sayHi('MK');
sayHi('Manish');

Because module scripts are automatically deferred until the end of HTML processing, you know that won't happen until all the HTML is loaded. This is covered by a great graphic in this section of the spec, duplicated here:

enter image description here

If you want to wait longer, until the load event (which doesn't fire until all images and such are loaded), use a modern event handler to do that:

import { sayHi } from './say.js';
sayHi('MK');
window.addEventListener("load", () => {
    sayHi('Manish');
});

If you need information from the element you hooked the event on, use a traditional function and access the element as this, or accept the event parameter and use event.currentTarget (you can also use event.target for the element that the event targets, which could be within the element you hooked the event on). So for instance, suppose you have:

<button type="button" data-name="Manish" id="btn-say-hi">

you could have:

import { sayHi } from './say.js';
document.getElementById("btn-say-hi").addEventListener("click", function() {
    sayHi(this.getAttribute("data-name"));
});

Also note that as Vikas Saini pointed out your say.js is using a string literal instead of a template literal (and although he/she didn't mention it, also has the wrong syntax for a substitution), so you'll actually see the text Hello { $user } instead of seeing Hello MK or Hello Manish. Either use a template literal with the correct form of substitution (${user}, not { $user }):

export function sayHi(user) {
    alert(`Hello, ${user}`);
}

or simple string concatenation:

export function sayHi(user) {
    alert("Hello, " + user);
}

Upvotes: 2

Vikas Saini
Vikas Saini

Reputation: 485

Classic case of String interpolation

Use

export function sayHi(user) { alert(`Hello, ${user}`);}

Notice ` in place of ' or "

Reference https://campushippo.com/lessons/how-to-do-string-interpolation-with-javascript-7854ef9d

For the Error, bind the window to load

window.addEventListener("load", () => {
    sayHi('testing');
});

Upvotes: 1

Related Questions