This is a beginner question. I just cannot figure out the answer as simple as it may be.
I have two files: One with a JavaScript function and the other with the HTML code. The JavaScript should build the elements of a menu.
This is what I have:
JavaScript (mynaivesdk.js):
async function buildMenu(element){
const webElements = [{"name": "Home", "href": "index.html"}, {"name": "Works", "href": "works.html"}, {"name": "Contact", "href": "contact.html"}]
var menu = document.getElementById(element);
webElements.forEach((webelement) => {
const row = '<li><a href="' webelement.href '">' webelement.name '</a></li>';
menu.innerHTML = row;
});
}
HTML:
<html>
<head>
<script type="module" src="mynaivesdk.js"></script>
<title>My Menu</title>
</head>
<body>
<h1>This is my menu</h1>
<ul id="mymenu" onload="buildMenu('mymenu')">
</ul>
</body>
</html>
The result is that nothing is displayed. There is no error. I am concluding my HTML is not invoking the JavaScript function at all.
This is what I would expect to have:
<html>
<head>
<script type="module" src="mynaivesdk.js"></script>
<title>My Menu</title>
</head>
<body>
<h1>This is my menu</h1>
<ul id="mymenu">
<li><a href=ïndex.html">Home</a></li>
<li><a href=works.html">Works</a></li>
<li><a href=contact.html">Contact</a></li>
</ul>
</body>
</html>
I know this should be extremely simple. I just cannot figure out the correct way of doing this.
Thank you!
CodePudding user response:
Call your function when the JS file loads and it will build your menu for you.
You'll need to add the defer
attribute to your <script>
tag. This simple attribute replaces the need to do the DOMContentLoaded
thing.
Here you go:
function buildMenu(menu) {
const webElements = [{
"name": "Home",
"href": "index.html"
}, {
"name": "Works",
"href": "works.html"
}, {
"name": "Contact",
"href": "contact.html"
}]
webElements.forEach((webelement) => {
const row = '<li><a href="' webelement.href '">' webelement.name '</a></li>';
menu.innerHTML = row;
});
}
buildMenu(document.getElementById('mymenu'));
<html>
<head>
<script defer type="module" src="mynaivesdk.js"></script>
<title>My Menu</title>
</head>
<body>
<h1>This is my menu</h1>
<ul id="mymenu">
</ul>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
There are a couple of things to know:
As epascarello pointed out in a comment, the
UL
element doesn't have aload
event, so thebuildMenu()
function will never fire.So, you need to call the buildMenu function, based on some event (a button press, hovering over a specific element, or - in this case - the document load event.
The document load event (
DOMContentLoaded
) is important because it is fired as soon as the elements are all present in the DOM. Before that, if you ran thebuildMenu
function, the#mymenu
element might not be there yet, and nothing will happen.This method is easily expanded, and you can add more function calls, etc, as you build-out your app. It is also worth noting that this is the standard way of structuring the loading/calling of JavaScript functions.
Here's what it looks like:
document.addEventListener('DOMContentLoaded', () => {
const myUl = document.getElementById('mymenu');
buildMenu(myUl);
});
function buildMenu(myEl){
const webElements = [{"name": "Home", "href": "index.html"}, {"name": "Works", "href": "works.html"}, {"name": "Contact", "href": "contact.html"}]
//var menu = document.getElementById('mymenu'); //not needed
webElements.forEach((webelement) => {
const row = '<li><a href="' webelement.href '">' webelement.name '</a></li>';
myEl.innerHTML = row;
});
}
<html>
<head>
<script type="module" src="mynaivesdk.js"></script>
<title>My Menu</title>
</head>
<body>
<h1>This is my menu</h1>
<ul id="mymenu" onload="buildMenu('mymenu')">
</ul>
</body>
</html>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
Element
doesn't haveonload
event.- You don't have to add the
async
keyword.
Please read about JavaScript Asynchronous
- You can either put your javaScript code before
</body>
inside a<script>
tag or just make a newjs
file.
<body>
.....
<!-- Here your change -->
<script>buildMenu("mymenu");</script>
</body>
- Please use template literals, it's better than string concatenation.
const row = `<li><a href="${element.href}">${element.name}</a></li>`;
The final code will be something like this.
In your script.js
file:
function buildMenu(menuID) {
const webElements = [
{ name: "Home", href: "index.html" },
{ name: "Works", href: "works.html" },
{ name: "Contact", href: "contact.html" }
];
var menu = document.getElementById(menuID);
webElements.forEach((element) => {
const row = `<li><a href="${element.href}">${element.name}</a></li>`;
menu.innerHTML = row;
});
}
In your index.html
file
<html>
<head>
<title>My Menu</title>
</head>
<body>
<h1>This is my menu</h1>
<ul id="mymenu">
</ul>
<script src="script.js"></script>
<script>
buildMenu("mymenu")
</script>
</body>
</html>