Github repo: https://github.com/leighhobson89/ChipshopChopper
I am having difficulties in forcing one .js
file to run its code before another one attempts to. The grit of the problem is that I am calling a function via a dispatch event in one file (lets call it 1.js
), and the function it calls is in the second file (lets call it 2.js
). However, even though it does call the function when the event dispatch triggers, the variable it is supposed to write to in that function is returning not defined (it is declared above the function in 2.js
)
I have tried declaring this variable in 1.js
before dispatching the event, and exporting it, but then I get the error saying you cannot assign to a constant variable. The whole point of this exercise is to have this constant in its own file because it is a big long list of DOM elements, and I dont want to have to keep calling document.getElementById()
every time I want to affect the innerHTML
of an element, so I created an event to trigger to call this function at a point in the code I want it to load it, i.e. after the elements are created but before they are requested to be changed.
I'd like a way, other than defer
or sorting the order in the HTML, or putting the script in the <head>
tag, all of which I have tried without success, to force it to initialize the variable in 2.js
before doing anything in 1.js
.
I will provide code samples if anyone wants to see them, but it is difficult to get a context without pasting vast swathes of code from multiple files, so apologies in advance for that.
From research online I tried:
defer
to try and make 1.js
load before 2.js
1.js
in the <head>
tagPromise
in the function that sets the elements variable, to resolve when elements has a value other than null or undefined (but I dont have a good command of async programming so it was maybe right or not)<script>
tags in the HTML file.1.js:
let elements;
export function setElements() {
elements = {
option1: document.getElementById('option1'),
option2: document.getElementById('option2'),
//etc
}
2.js
import {getElements, setElements} from './1.js'
document.addEventListener('titleScreenCreated', setElements);
const titleScreenCreatedEvent = new Event('titleScreenCreated');
createGameWindow(titleScreenCreatedEvent);
//code that creates various elements
document.dispatchEvent(titleScreenCreatedEvent);
console.log(getElements());
//code that changes elements
// getElements().option1.innerHTML = "hello world";
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Your Game</title>
</head>
<body>
<div class="clock">00:00:00</div>
<script type="module" src="actions.js"></script>
<script defer type="module" src="1.js"></script>
<script type="module" src="ui.js"></script>
<script type="module" src="2.js"></script>
</body>
</html>
Thanks for linking the GitHub repository, this way I was able to reproduce your problem.
Your game tries to create the UI when the modules are not fully loaded yet. I suggest creating a main
function to serve as the entry point for your application and moving every bit of game initialization into that function. Make sure to call it after all modules are initialized, for example, use the DOMContentLoaded event.
function main() {
document.addEventListener('titleScreenCreated', settlements);
const titleScreenCreatedEvent = new Event('titleScreenCreated');
createGameWindow(titleScreenCreatedEvent);
createTitleScreen();
gameLoop();
}
document.addEventListener('DOMContentLoaded', () => {
main();
});
On a more general note, you only see this kind of problem when there are dependency cycles around. When this happens, there is no reliable way to control the loading order, you have to restructure the application. The best way around it is to avoid cycles altogether, if possible.