Search code examples
javascriptmaterializesidenav

Materialize sidenav collapsible won't work within a separate JS file


Sorry if this has been answered previously; I've dug around but can't find it. I'm using the Materialize sidenav by calling M.AutoInit() which works for me until I try putting it in a separate Javascript file. I've been able to set up my footer this way so I don't have repeat code, but this doesn't seem to work for the sidenav. The sidenav shows up but the collapsible part will not open.

I think the problem is it doesn't like calling the collapsible part from HTML that is being inserted dynamically. But I tried separating out the collapsible portion (using 2 different querySelectors) which did not work either. If I were to put at least part of the sidenav back into my HTML page, it would defeat the purpose of me doing this.

Any thoughts or solutions? Thanks for looking at it!

document.addEventListener("DOMContentLoaded", () => {
  M.AutoInit()

  document.querySelector('header').insertAdjacentHTML('afterbegin',
    `<ul id="slide-out" class="sidenav sidenav-fixed">
      <li>
        <a
          href="https://www.greece.org/"
          target="_blank"
          rel="noopener noreferrer"
          >HEC Main</a
        >
      </li>
      <li>
        <a href="index.html" class="sidenav-close" rel="noopener noreferrer"
          >Home</a
        >
      </li>
      <li class="no-padding">
        <ul class="collapsible collapsible-accordion">
            <li>
            <button class="collapsible-header">
              History<i class="material-icons">arrow_drop_down</i>
            </button>
            <div class="collapsible-body">
              <ul class="sidenav-close">
                <li>
                  <a href="a-brief-review.html">A Brief Review</a>
                </li>
                <li><a href="philosophers-list.html">Philosophers List</a></li>
                <li><a href="philosophers-map.html">Philosophers Map</a></li>
                <li><a href="the-beginning.html">The Beginning</a></li>
                <li><a href="socrates.html">Socrates</a></li>
                <li><a href="plato.html">Plato</a></li>
                <li><a href="aristotle.html">Aristotle</a></li>
                <li>
                  <a href="bibliography-references.html"
                  >Bibliograpy / References</a
                  >
                </li>
              </ul>
            </div>
          </li>
        </ul>
      </li>
      <li class="divider"></li>
      <li>
        <a href="media.html" class="sidenav-close">Media</a>
      </li>
      <li>
        <a href="events.html" class="sidenav-close">Events</a>
      </li>
    </ul>`)

  document.querySelector('main').insertAdjacentHTML('afterend',
    `<footer class="page-footer">
        <div class="container">
          <p class="center-align">
            Philosophy is sponsored by
            <a
              href="https://www.greece.org"
              target="_blank"
            >
              www.greece.org 
            </a> | &copy; 2021 All Rights Reserved.
          </p>
        </div>
       <div class="fixed-action-btn">
        <a href="#top" class="btn-floating btn-large" style="background-color: silver;">
          <i class="large material-icons">arrow_upward</i>
        </a>
      </div>
    </footer>`)
})

Solution

  • Initialisation is a one time thing - it scans the document for the matching selector, and runs the initialisation on it. So, always run the initialisation AFTER any dynamic content is added. If you add stuff on the fly, just run the init again.

    Codepen.

    document.addEventListener('DOMContentLoaded', function() {
       // Always add stuff to the page BEFORE running the init
       // Anything hardcoded to the page will be fine if wrapped in a document ready.
       M.AutoInit();
       // Anything added after the init will NOT be initialised. It's a one time thing. Run the init at the end of any dynamic additions.
    });