0

I am using W3-Schools "include-html" https://www.w3schools.com/howto/howto_html_include.asp

It states that you can use multiple snippets. My plan was to include a header and a footer for each page by using this method.

On my index.html page I have this:

<!doctype html>
<html lang="en">
    <!--Include Content-->
    <script src="assets\scripts\include_content.js">
    </script>
</head>

<body>
    <header>
        <div include-html="header.html"></div>
    </header>
    <footer>
        <div include-html="footer.html"></div>
    </footer>
    <!--Scripts-->
    <script>
        includeHTML();
    </script>
</body>

</html>

The scripts are a direct copy and paste from W3 (with minor changes to attribute names):

function includeHTML() {
  var z, i, elmnt, file, xhttp;
  /* Loop through a collection of all HTML elements: */
  z = document.getElementsByTagName("*");
  for (i = 0; i < z.length; i++) {
    elmnt = z[i];
    /*search for elements with a certain attribute:*/
    file = elmnt.getAttribute("include-html");
    if (file) {
      /* Make an HTTP request using the attribute value as the file name: */
      xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function () {
        if (this.readyState == 4) {
          if (this.status == 200) {
            elmnt.innerHTML = this.responseText;
          }
          if (this.status == 404) {
            elmnt.innerHTML = "Page not found.";
          }
          /* Remove the attribute, and call this function once more: */
          elmnt.removeAttribute("w3-include-html");
          includeHTML();
        }
      };
      xhttp.open("GET", file, true);
      xhttp.send();
      /* Exit the function: */
      return;
    }
  }
}

I can get the footer to run if I delete the include-html="header.html" so I know the linking is there. But I can not get both footer and header to run.

Both footer and header pages are currently identical except for the message so I know where the message is coming from.

Can you see if I am missing something or why the second <div include-html="footer.html"></div> is not working?

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
Paul Davis
  • 495
  • 4
  • 14
  • Remove `return` from the end – Konrad Oct 27 '22 at 19:17
  • 2
    As a professional web developer and corporate IT trainer for 30 years, I can unequivocally state that you should stay as far away from W3 Schools as possible as they are well know to have incomplete, outdated, or just plain incorrect information. Instead, use the authoritative source for web development documentation, the [Mozilla Developer Network (MDN)](https://developer.mozilla.org/en-US/). – Scott Marcus Oct 27 '22 at 19:22
  • 2
    In your W3 case, they are showing a way that "works", but it's invalid HTML. You can't just make up your own attributes in HTML (which is what `include-html` is). They should be using CSS class names or `data-*` attributes. – Scott Marcus Oct 27 '22 at 19:25
  • Also, [`getElementsByTagName()` should be avoided](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474), especially when used in conjunction with loops. This whole example they've provided uses incorrect and outdated approaches to solving this use case. – Scott Marcus Oct 27 '22 at 19:28
  • 1
    You are also missing the opening `` tag. – Scott Marcus Oct 27 '22 at 19:35
  • 1
    The problem stems from a typo when you renamed the attribute. Change removeAttribute("w3-include-html") to removeAttribute("include-html"). The original W3Schools code works, though you could update the attribute name to "data-include-html" to satisfy @ScottMarcus concerns. – Yogi Oct 28 '22 at 05:54
  • So, yes, the w3 way does work. I didn't realise you couldn't change the name of that attribute. The opening tag is there, sorry I accidentally deleted it while removing some of the erroneous code. Thanks for the fix, the original is the way" – Paul Davis Oct 28 '22 at 16:09

1 Answers1

2

For all the reasons I mentioned in my comments to your question, you should just abandon the W3 Schools approach.

The simplest solution is to just use HTML <iframe> elements and no JavaScript whatsoever:

<!doctype html>
<html lang="en">
  <head>
    <title>Page Title Here</title>
    <meta charset="utf-8">
  </head>
  <body>
    <header>
        <iframe src="header.html"></iframe>
    </header>
    <footer>
        <iframe src="footer.html"></iframe>
    </footer>
  </body>
</html>

But, if you do need a JavaScript solution, using AJAX (XMLHttpRequest) is correct, but with the modern syntax, rather than what W3 Schools shows:

function includeHTML(fileName, destination) {
  let xhr = new XMLHttpRequest();
  
  // Establish the callback:
  xhr.onreadystatechange = function () {
  
    // Is the response ready?
    if (this.readyState == 4) {  
      // Was the response successful?
      if (this.status == 200) {
        destination.innerHTML = this.responseText;
      } else {
        console.log("Response was received but not successful.");
      }
    } else {
      console.log("Response is not ready.");
    }
  }
  
  // Initiate the request:
  xhr.open("GET", fileName, true);
  xhr.send();
}

// Call the function with the file to include and a reference to the 
// element to populate with the contents
includeHTML("header.html", document.querySelector(".header"));
includeHTML("footer.html", document.querySelector(".footer"));
<!doctype html>
<html lang="en">
  <head>
    <title>Page Title Here</title>
    <meta charset="utf-8">
  </head>
  <body>
    <header>
        <div class="header"></div>
    </header>
    <footer>
        <div class="footer"></div>
    </footer>
    <!--Reference and load your scripts just before the closing
        body tag so that by the time the HTML parser reaches
        this point in the document, all the HTML will have been
        parsed into memory.  -->
    <script src="assets\scripts\include_content.js"></script>
  </body>
</html>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • Thank you for taking the time to show me this. I appreciate that and the effort you have gone through to show this. I am trying the iframe method as the simplest - I am not sure what sort of issues I will run into with this, but I will do my best to see how it works. Thanks again for your input. I am trying both ways to see which is the best. – Paul Davis Oct 28 '22 at 16:15