Search code examples
javascriptfor-loopsafarifor-of-loop

Javascript for...of doesn't work in Safari


Currently I am trying to build a simple sidenavigation that appears/disappears whenever one of the "toggleSidenav" buttons is clicked (there are multiple).

It seemed to work fine when testing with Firefox and Chrome but today when I tried to open my page with Safari (desktop and mobile version) the buttons didn't do anything.

The problem seems to be the for-of-loop I used but checking the reference of the for...of, Safari should support it.

My code:

for (var btn of document.getElementsByClassName("toggleSidenav")) {
    btn.addEventListener("click", function() {
        var style = window.getComputedStyle(document.getElementById("sidenav"));

        if (style.getPropertyValue("display") == "none") {
            openSidenav();
        } else {
            closeSidenav();
        }
    });
}

I probably need to use an alternative method anyway because the for...of is only supported by IE/Edge 12+ but I would still like to know why this didn't work.


Solution

  • Safari supports for-of with arrays. getElementsByClassName returns a NodeList, which is array-like, but isn't a true array, so you need to convert it to an array. Since you're requiring ECMAScript 6 support for for-of, you can use Array.from() for this conversion, rather than some old idioms like Array.prototype.slice.call().

    for (var btn of Array.from(document.getElementsByClassName("toggleSidenav"))) {
      btn.addEventListener("click", function() {
        var style = window.getComputedStyle(document.getElementById("sidenav"));
    
        if (style.getPropertyValue("display") == "none") {
          openSidenav();
        } else {
          closeSidenav();
        }
      });
    }
    
    function openSidenav() {
      document.getElementById("sidenav").style.display = 'block';
    }
    
    function closeSidenav() {
      document.getElementById("sidenav").style.display = 'none';
    }
    <button class="toggleSidenav">
      Toggle 1
    </button>
    <button class="toggleSidenav">
      Toggle 2
    </button>
    <button class="toggleSidenav">
      Toggle 3
    </button>
    <div id="sidenav">
      Side Nav
    </div>