Unable to access global variable in javascript? - javascript

I am trying to access a var one file from another file. Here is what I have:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="btn">Global</button>
<script src="/test.js"></script>
<script src="/testpass.js"></script>
</body>
</html>
test.js:
export var globalVariable = {
output: "test this"
};
testpass.js:
import { globalVariable } from './test.js'
document.getElementById("btn").addEventListener("click", function(){
alert(globalVariable.output);
});
Nothing happens. I also tried doing
var globalVariable = {
output: "test this"
};
and then simply accessing it from another file as demonstrated in this answer:
Call variables from one javascript file to another but it did not work. Tried exporting it as mentioned in this answer: Can I access variables from another file? as well but no success. I am using sublime text and vue.js and it does not work for both of them.
In addition if I do something like this:
import { globalVariable } from '.test.js'
document.getElementById("btn").addEventListener("click", function(){
alert("Not printing the globalVariable here");
});
the entire javascript file seems to fail and doesn't work at all when called in the HTML file.

You should be getting an error from the browser's JavaScript engine in the web console. To use import and export, you have to treat your code as a module. Your script tags don't, they treat the code as just script. To treat testpass.js as a module, you must use type="module":
<script src="/testpass.js" type="module"></script>
No need to list test.js, testpass.js will load it. So:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="btn">Global</button>
<script src="/testpass.js" type="module"></script>
</body>
</html>
Sadly, we can't show modules in SO's Stack Snippets, but if you make those changes, this codesandbox example is what you end up with (except I changed src="/testpass.js" to src="./testpass.js").
Note that globalVariable isn't a global variable (which is a Good Thing™). It's a local variable within test.js that it exports. Any other module can import it, but it's not a global.

Related

make javascript module global?

I am trying to execute a function from within a script. It shows no error but also doesnt execute the function.
file.mjs
function test() {
console.log("test")
}
This is my html:
index.html
<head>
<script type="module" src="file.mjs">
</head>
<body>
<button type="button" id="Submit">Submit</button>
<script>
document.getElementById('Submit').addEventListener('click', test);
</script>
</body>
This worked fine using 2 separate scripts, to make it global I was using type="text/javascript".
But since my file.mjs is actually importing a library I had to set it as type="module" and the function wont execute. Is there a way to make the module scope global?
Before I go on, there's a big problem that needs addressing:
Your syntax is wrong. If you want to import a script, that tag must have the src attribute and nothing within the tag. If you want to execute an "inline" script, it should NOT have the src attribute, so what you should have is two script tags, one to import the module, the other to execute your inline code.
Now, I'm not sure what you mean by "global". To obtain true "globalness", you would have to define your variable in the global object (window or globalThis) like so:
// file.mjs
function test() { ... }
window["test"] = test;
Then in your regular script you could just do document.getElementById('Submit').addEventListener('click', test);.
That sort of completely destroys the purpose of JS modules though, as it's supposed to be an "import/export" model.
Ignoring the "global" part of your question: if you want to use modules for what they're worth, you would be importing and exporting them, and you would only (almost always) link a <script type="module"> in your HTML if it only imports and never exports (exporting would be useless). The reason you need type="module" is to tell the browser that you're operating on modules so it'll allow you to import/export. With that said, your code would look like this:
// file.mjs
export function test() { ... }
And in your HTML, you would only need one script tag (that goes right before the ending body tag):
<script type="module">
import { test } from "/path/to/file.mjs";
document.getElementById('Submit').addEventListener('click', test);
</script>
I hope that clears it up for you, and docs if you need them.

ES6 modules in Chrome

I'm trying to use ES6 modules in Chrome. From all the examples I've looked at the following seems to be the right way to do it, but when I run it in Chrome's developer tools I get this error message...
uncaught SyntaxError: Unexpected token {
...highlighting the import statement in the module (script1.js, below) that's trying to import the module. I've seen a lot of references to problems like this but none of the suggestions to remedy the situation have worked for me. If you could see what I'm doing wrong, I'd sure appreciate your help...
here's the html...
<html>
<head>
<script src="lib1.js" type="module"></script>
<script src="script1.js"></script>
</head>
<body>
</body>
</html>
here's the module (lib1.js)...
export function doSomething() {
alert("in module lib1");
}
here's the script (script1.js) that tries to import the module...
import { doSomething } from "lib1.js";
doSomething();
EDIT:
After about an hour of head scratching and finding out that my answer (pre-edit) was downvoted I got to this:
lib.js:
function doSomething() {
console.log('in module lib');
}
export {doSomething};
script.js:
import { doSomething } from './lib.js';
doSomething();
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script type="module" src="script.js"></script>
</body>
</html>
lib.js, script.js, and index.html are on the same directory.
I added .js to import { doSomething } from './lib.js'; because it didn't work otherwise. According to Mozilla certain bundlers may permit or require the use of the extension for the module-name.
But this only worked on Firefox Quantum (ver. 62.0.3).
I enabled Experimental JavaScript on Chrome (ver. 70.0.3538.77) on:
chrome://flags/#enable-javascript-harmony
with no signs of success, but considering this worked on Firefox and that
this compatibility table shows both Chrome and Firefox being on the same level of compatibility is making me more confused so I'll probably end up asking a question regarding this whole thing.
Your code won't work in any browser. This is the right way to do it:
index.html
<html>
<head>
<script src="script.js" type="module"></script>
</head>
<body>
</body>
</html>
lib.js
export function doSomething() {
alert("in module lib1");
}
script.js
import { doSomething } from "./lib.js";
doSomething();
<script src="script.js" type="module"></script> is the key ... shame on error message in Chrome
Thanks, it finally works for me, though this was really confusing to me at first!
In case anybody's interested, there are two confusing things that finally made it for me after walking around in circles for a while:
You add type="module" to the <script> into which you import the module, not the module itself. In fact, there is only one <script> in the index.html file. The modules are then only imported from within the index.js file.
you need to import the file in the index.js with extension, such as:
import search from "./search.js";
I tried this on Firefox.

Importing p5 into a Vue app

I added the p5 library into the dom like so...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>App</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/addons/p5.dom.js"></script>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>
So technically I should be able to grab it via window variable within my Vue code...
<template>
<div id="app">
<h1>Hey my app!</h1>
</div>
</template>
<script>
export default {
name: 'app',
mounted() {
console.log(window.p5) // it's found
window.p5.createCanvas(640, 480);
},
}
</script>
Yet error logs show:
TypeError: window.p5.createCanvas is not a function. After logging window.p5, I can see that it's there. Just not createCanvas(). Which makes me think it's not fully there to begin with. Has anyone experienced this problem? How can I successfully import p5 and make use of it in my Vue app?
You can't just randomly call the createCanvas() function. You have to do it after the setup() function is called.
More info here: Why can't I assign variables using p5 functions and variables before setup()?
To fix your problem, you either need to put your call inside the setup() function, or you need to use on-demand instance mode (as explained in the above link) or instance mode (as explained here).

How to correctly execte function from external file onload?

I have a function myModule.myFunction in a larger external script mymodule.js that is executed on load. Everything seems to work fine. But now I have added
"use strict";
at the top of the external script. And I get a
TypeError: MyModule is undefined
and the page stops working. So I am wondering where I did something problematic. Here is the structure of my page (unfortunately, I did not manage to produce a minimal example):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- Some html here -->
<script src="mymodule.js"></script>
<script>
function myOnload() {
myModule.myFunction();
}
window.addEventListener('load', myOnload, false);
</script>
</body>
</html>
Here is what the MyModule in mymodule.js looks like:
var myModule = (function(){
// stuff
})();
In myModule.js you need to explicitly assign myModule to the window object (when using "use strict").
Change it to window.myModule = ...
Reason: in sloppy mode, undeclared variables are automatically added as properties on the global object. In strict mode they are not )to avoid accidental interference).

Creating an instance in addOnLoad method of dojo doesn't have global scope

I've a Utils class in JavaScript. Below is the source code of that JavaScript.
function UtilityMethod(){
this.testMethod=function(){
alert("Test method is called");
}
}
Above code is included in Utils.js file.Now I need to create an instance of UtilityMethod in my HTML File. I've referenced Utils.js in my HTML file. Below is my HTML Code.
<html>
<head>
<title> New Document </title>
<script type="text/javascript" src="/dojo/dojo.js"></script>
<script type="text/javascript" src="/js/Utils.js"></script>
</head>
<body>
<script type="text/javascript">
dojo.addOnLoad(function(){
var Utils = new UtilityMethod();
});
</script>
TestMethodCall
</body>
</html>
But when I click on the HyperLink, it is giving me the error Utils is not defined. But even though I'm clicking on the link after page load, why is it still giving the error?
I need to include the instance creation in dojo.addOnLoad() method. Can you please suggest if there are other easy alternatives to this?
I know that we can do this using dojo.connect(), but is there another approach to do this. If we are using dojo.connect, we have to make changes to lot of code.
It's because Utils is created in a function; it won't be available outside the function. A nice explanation of this scoping behavior can be found here. To make this work, you'll need to tell the browser that Utils is a global variable:
window.Utils = new UtilityMethod();
Now, Utils is set on the window object thus making it accessible anywhere (A nice feat of the window object is that its properties are available without the window. prepended, so you can still use Utils.testMethod as normal)

Categories

Resources