What I want to achieve:
hrefs
in the list
with class="listen"
.div
with id="SelectedText"
with the content of the chosen file.<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Read file into div</title>
<article>
<h1>My HTMl</h1>
<ul class = "listen">
<li><a class="loc" href="file1.html">Select file 1</a>
<li><a class="loc" href="file2.htm">Select file 2</a>
<li><a class="loc" href="file2.txt">Select file 3</a>
<li><a href="https://example.com/">Load external file in new window with noopener</a>
</ul>
<h1>Please find selected content below:</h1>
<div id = "SelectedText">
<p>Replace me
</div>
<script> magic here </script>
</article>
<!-- Local file -->
<p>file i contains for example:
<h1>Ipsum dolor sit amet</h1>
I tried:
<!DOCTYPE html>
<html lang="nl">
<meta charset="utf-8">
<title>Test</title>
<nav>
<ul>
<li><a href="#" onclick="loadDoc('/nieuws.htm'); return false;">Nieuws</a>
<li><a href="#" onclick="loadDoc('/teams/teams.htm'); return false;">Teams</a>
<li><a href="#" onclick="loadDoc('/links/links.htm'); return false;">Links</a>
</ul>
</nav>
<main id="content">
<p>Replace me
</main>
with JavaScript function:
<script>
// Load external HTML document in div.
function loadDoc(x) {
fetch(x)
.then((result) => {
if (result.status != 200) { throw new Error("Bad Server Response"); }
return result.text();
})
.then((content) => {
document.getElementById("content").innerHTML = content;
})
.catch((error) => { console.log(error); });
}
</script>
But I find a solution with event-handlers more elegant.
Update How to open the file in new window when an "Access-Control-Allow-Origin" error occurs.
Note: After the catch (err) I would like to execute the default behaviour, e.g. load the file in a separate window (_blank). No idea how to do this.
Application
Consider a website with choices:
Then if the user select choice 1 I would like to put the text regarding this choice in the rest of the page.
Note
I have a small old website. My question is about menu management: how can I insert web page content within the main page? Over time, I have realised that using an iframe is the most obvious solution.
Based on this similar answer on how to fetch partial HTML content from files
addEventListener
instead of inline JS like onclick
event.preventDefault()
to prevent the default browser behavior (follow anchors)Having HTML partials like: page1.html
in the root of your project
pageN.html
<h1>This is page N</h1>
this would be your main page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Read file into div</title>
</head>
<body>
<h1>My HTML</h1>
<ul class="listen">
<li><a href="file1.html" class="loc">Load file 1</a>
<li><a href="file2.html" class="loc">Load file 2</a>
<li><a href="file3.html" class="loc">Load file 3</a>
</ul>
<h1>Please find selected content below:</h1>
<div id="SelectedText">
<p>Replace me</p>
</div>
<script>
const loadPartial = async (elAnchor, elTarget) => {
const file = elAnchor.getAttribute("href");
try {
const res = await fetch(file);
const html = await res.text();
const domp = new DOMParser();
const doc = domp.parseFromString(html, "text/html");
elTarget.innerHTML = ""; // clear old content
elTarget.append(doc.documentElement);
} catch (err) {
console.error(err);
open(file, "_blank", "noopener,noreferrer");
};
};
const elTarget = document.querySelector("#SelectedText");
const elListen = document.querySelector(".listen");
elListen.addEventListener("click", (evt) => {
const elAnchor = evt.target.closest(".loc");
if (!elAnchor) return;
evt.preventDefault(); // Prevent browser following the anchor
loadPartial(elAnchor, elTarget);
});
</script>
</body>
</html>
I've used DOMParser for injecting elements into your page as a security measure (XSS Vulnerability). If you trust the content that's being inserted you might instead use this simpler (and faster) solution inside the try
block:
const res = await fetch(file);
const html = await res.text();
elTarget.innerHTML = html;
Tip:
developers in need to dynamically (AJAX) populate/fetch partials into their page often forget that, as the page content drastically and meaningfully changes, there's the need for the visitors to navigate back / forward the history, bookmark or share the current page's content direct link. With the above that's impossible, so I would suggest to explore the History API - namely the pushState, popState, and replaceState methods to achieve single-page application routing.