Cannot read property 'classList' of null - responsive menu

Hi,

I posted my question in CMS Wordpress forum but it is also JavaScript related as the issue is JS related. The script works if I put it in in the footer.php of a child theme (for those who are not familiar with WordPress - child theme is some php files run on top of a parent theme php files). The final output of a webpage is produced dynamically by running several php files called ‘templates’. However, the scirpt is not working if put in the external js file linked to child theme via functions.php file.

My understanding is that the script is trying to remove navTop.classList.remove(“responsive”); however fails to do so.

The CSS can be found here http://buildandtest.atspace.cc/css/style-flex.css

Please see link below with my original question.

https://www.sitepoint.com/community/t/twentysixteen-child-theme-menu-cannot-read-property-classlist-of-null/349251

I appreciate any advice

Hi @810311, that means you’Re trying to access an element which does not exist yet when the JS is running. To solve this, you have to options: either actually include the script in the footer to ensure the DOM is ready; the canonical way to do this in WP would be setting the $in_footer flag to true like so:

wp_enqueue_script(
  'my-menu',
  get_template_directory() . '/js/menu.js', 
  [], 
  '0.4.2',
  true // <- this one
);

Alternatively, you might wait for the DOM within your JS; basically you can just replace your IIFE with the appropriate event handler:

window.addEventListener('DOMContentLoaded', function () {
  // ... 
})

Best practice would be doing the former so parsing and executing the JS doesn’t block the loading of the content; but it won’t hurt to wait for the DOM anyway in case you want to reuse the JS somewhere else, for instance.

1 Like

I am trying to convert this site http://buildandtest.atspace.cc/ into twentysixteen child theme. It appears that /js/menu.js in my child theme is not working as nothing happens when the ham icon button is clicked (pls.see my site link above to check correct behavior). On inspecting via Google Chrome Inspect I am getting the following errors:

Uncaught TypeError: Cannot read property ‘classList’ of null at mediaqueryresponse (menu.js?ver=5.3.2:19) at menu.js?ver=5.3.2:10 at menu.js?ver=5.3.2:31 mediaqueryresponse @ menu.js?ver=5.3.2:19 (anonymous) @ menu.js?ver=5.3.2:10 (anonymous) @ menu.js?ver=5.3.2:31

Any advice is appreciated

header.php in child theme

<header class="header" id='myTopnav'>

<?php
 wp_nav_menu(
             array(
                  'theme_location'=> 'topnav',
                  'container' => 'nav',
                  'menu_class' => 'topnav',
                  'menu_id'    => 'myTopnav',
                  )
 );?>

<button class="ham-icon"><span class="fa fa-bars fa-2x"></span></button>

</header>

/js/menu.js in child theme

(function () {
  var mql = window.matchMedia("screen and (max-width: 960px)");
  //detect media query

  var navTop = document.querySelector(".header");
  //return first element within the document that matches .header

  var toggle = document.querySelector(".ham-icon");

  mediaqueryresponse(mql);
  //ensures that addListener function is executed when the page loads, by default addListener only fires when state of the window changes
  mql.addListener(mediaqueryresponse);

  function mediaqueryresponse(mql) {
    if (mql.matches) {
      toggle.addEventListener("click", clickMenu);
      //if media query matches, execute click or clickMenu event
    } else {
      navTop.classList.remove("responsive");
      //otherwise remove .responsive
      toggle.removeEventListener("click", clickMenu);
      //and remove EventListener
    }

  }

  function clickMenu() {
    navTop.classList.toggle("responsive");
  }

})();

The above code did work when I used with a theme created from scratch, however, its not working with child theme.

I removed script from the footer and modified functions.php in my child theme as follows:


function register_style ()

{ wp_enqueue_script ('menu-responsive', get_stylesheet_directory_uri() . '/js/menu.js'), 
  '0.4.2', [], true);}

{ wp_enqueue_style ('child-style', get_stylesheet_directory_uri() . '/css/child-style.css');}

{ wp_enqueue_style ('font-awesome', '//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css');}

add_action ('wp_enqueue_scripts', 'register_style');

Its giving me syntax error. Am I missing something?

Please disregard my last reply - I found the error - I put an extra ) after /js/menu.js (see above code)

Following is the version that worked for me:

{wp_enqueue_script ('menu-responsive', get_stylesheet_directory_uri() . '/js/menu.js', 
  '0.4.2', [], true);}

@m3g4p0p can you explain what are those square brackets []which come after version '0.4.2 in the above syntax are used for? I tried googling those but can’t find any info either in Codex or elsewhere…

I also tried using your second suggestion window.addEventListener('DOMContentLoaded', function () { // ... })

Question: is it supposed to work only when JS is linked via wp_enqueue_script? I tried commenting out wp_enqueue_script in my function.php out of curiosity and it didn’t work

Also, should it be closed with }) or I should add () after it…as in the original code which is “The second part creates the immediately invoked function expression”

It’s a list of dependencies for your script – here’s the link again:

https://developer.wordpress.org/reference/functions/wp_enqueue_script/#parameters

Well if you don’t load the script then it won’t run, obviously… or did you then include it otherwise (such as with a hard-coded script tag)?

No, the purpose of the extra () after the function expression is to immediately invoke it; in the case of an event handler however you specifically don’t want to call it right away but only when the event of the given kind occurs… see here for details.

1 Like

Sorry I am new to JS :slightly_smiling_face: I checked that link before but didn’t find anything specifically about those square brackets. Here’s the list of parameters wp_enqueue_script( $handle , $src , $deps , $ver , $in_footer ); can you tell me which parameter it is?

It’s the 3rd.

So it’s ‘deps’ and Default value is array(). Can you tell me why we use brackets instead? What do they do? Sorry I didn’t find that in that link…

[] is an empty array.

2 Likes

Thanks a lot for your help @m3g4p0p and @m_hutley. Its very hard to find professional advice these days. Hope you don’t mind if I continue to ask questions if I get stuck.

2 Likes