Home > Enterprise >  querySelector across HTML Pages....>
querySelector across HTML Pages....>

Time:01-02

I have a site with the following format: Main page (called index.html) contains:

  • Header
  • Main Section
  • Footer

The header contains a Hamburger icon which opens up a navbar when clicked with sub menus and sub-sub menus, mostly populated from JS scripts that build up the navbar from Nodejs & MySQL call results.

Because the NavBar is quite complicated and I have lots of different pages to my site, I decided to extract the whole header into its own html file (called header.html) and import header.html into a div as the header of index.html, making it easier to maintain just one html page instead of making the same changes to all html pages.

The way I import the header (called header.html) is with this function (in a seperate file called headerJS.js):

      const headerPage = '/public/html/header.html';
      const headerDiv = document.getElementById('header_container');

      function loadHeader() {
        const xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function() {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            {
                headerDiv.innerHTML = xmlHttp.responseText;
            }
        };
        xmlHttp.open("GET", headerPage, true); // true for asynchronous
        xmlHttp.send(null);
      }
      loadHeader();

That works fine in that it imports my header.html into my index.html file. However, when I click on the hamburger icon, nothing happens and the console tells me toggle is null - toggle is the name of the const that holds the reference to the name of the class on the hamburger icon as follows:

  /* Hide - Show the Menu Items if click on the Hamburger Icon */
  const toggle = document.querySelector('.navBarToggle');
  const menu = document.querySelector('.menu');
  
  function toggleMenu() {
      if (menu.classList.contains("active")) {
          menu.classList.remove("active");
          document.querySelector(".navbar").style.setProperty("padding", "0");
          toggle.querySelector("a").innerHTML = "<i class='fas fa-bars'></i>";
      } else {
          menu.classList.add("active");
          toggle.querySelector("a").innerHTML = "<i class='fas fa-times'></i>";
          document.querySelector(".navbar").style.setProperty("padding", "15px");
      }
  }
  toggle.addEventListener('click', toggleMenu);

If I open header.html and click on the icon, it opens up just fine and loads the whole NavBar, but if I click it from index.html, then nothing happens.

I think it may be because when loading header.html inside index.html, then the querySelector cannot find .navBatToggle because document.querySelector is looking for navBarToggle inside of index.html insted of header.html.

I did some googling obviouly and found something that sounds interesting but I dont quiet understand it as Im new to WebDev about shared web workers. Could that solve my issue and if so, is there a resource out there that explain how they work in a simple manner - didnt quite understand the explanation on MDN).

If there is another solution, can you point me in the right direction please? I tried to point to window.querySelector instead of document.querySelector thinking the window would apply to the whole site instead of just the index.html document but it made no difference.

Is there a way, by clicking the icon from the index.hmtl page, to make the query selector look for the .navBarToggle class inside the header.html page instead of document.querySelector which obviously refers to index.html?

Thank you in advance. M.

CodePudding user response:

You're right.

Your idea look like component in React.js and any others.

But, in static html page's drawing, If you load any other html files as Ajax, those are not applied corresponding your way, it is why loading time - window.document object will read at different time.

Ah, think your way is - loading as text. Exactly, It is text-loading.

I'm not recommend these ways.

And then, you could use AngularJS otherwise.

This is my suggestion is.

Thanks.

CodePudding user response:

Event listeners cannot be added to any tag created after page has loaded. You need to add the event listener to #header-container if that's the tag the navbar is being attached to (or more logically the footer but I can only go by what you actually posted -- so adjust accordingly).

    /*
   Add the listener to a parent tag that has existed
   before the page has loaded
   */
   document.getElementById('header_container').addEventListener('click', toggleMenu);

Add a condition to the event handler toggleMenu(e) that will accept only when the user clicks .navBarToggle

    if (clicked.matches('.navBarToggle')) {...

See event delegation for details

// Pass the Event Object
function toggleMenu(e) {
  // This is the tag the user actually clicked
  const clicked = e.target;
  const menu = document.querySelector('.menu');
  /*
  if clicked has class .navBarToggle
  then do whatever...
  */
  if (clicked.matches('.navBarToggle')) {
    if (menu.classList.contains("active")) {
      menu.classList.remove("active");
      document.querySelector(".navbar").style.setProperty("padding", "0");
      toggle.querySelector("a").innerHTML = "<i class='fas fa-bars'></i>";
    } else {
      menu.classList.add("active");
      toggle.querySelector("a").innerHTML = "<i class='fas fa-times'></i>";
      document.querySelector(".navbar").style.setProperty("padding", "15px");
    }
    // Wrap the whole thing in this if statement
  }
}

/*
Add the listener to a parent tag that has existed
before the page has loaded
*/
document.getElementById('header_container').addEventListener('click', toggleMenu);
   <!--Before Page Loads BEGIN-->
<div id='header_container'>
  <!--After Page Loaded BEGIN-->
  <button class='navBarToggle'></button>
  <nav class='menu'>
    <a></a>
  </nav><!--After Page Loaded END-->
</div><!--Before Page Loads END-->

  • Related