0

I'm working with Craft CMS and using javascript to load pages via AJAX. I use a global javascript variable to determine if my navigation menus is open or closed. Simple menuOpen = false or menuOpen = true. And then to open or close the menu:

$(".header a.nav").on("touchstart click", function(e){
  e.stopPropagation();
  e.preventDefault();

  if ( menuOpen == true ){
    closeMenu();
  } else if ( menuOpen == false ) {
    openMenu();
  }
});

openMenu = function() {
  $("body").addClass("menu-open");
  $("nav.menu").removeClass("is-closed").addClass("is-open");
  $("header a.nav").addClass("x").removeClass("menu");
  menuOpen = true;
}

closeMenu = function() {
  $("body").removeClass("menu-open");
  $("header a.nav").addClass("menu").removeClass("x");
  $("nav.menu").removeClass("is-open").addClass("is-closed");
  menuOpen = false;
  setTimeout(function(){
    $("nav.menu").removeClass("is-closed");
  }, 150);
}

When I change pages via AJAX I have to close the menu, so in my AJAX success function, I run closeMenu() to ensure it's closed when the new page is revealed.

$.ajax({
  type: 'POST',
  url: href,
  data: {},
  success: function(result){
    // Add in new content
    $main.html(result);
    // close menu
    closeMenu();
    // lots of other stuff omitted here to show you the relevant part
  }
});

My problem is that after an AJAX page load, when I go to open the menu again it appears as if the global variable menuOpen is not being read correctly, or the if statement is failing somehow.

The result is that the menuOpen and menuClose functions appear to both run at the same time, even though the if statement only allows one or the other to run. This means the menu can never open after any AJAX page load because it closes simultaneously to opening.

Is there something wrong with the way I'm using/changing variables, or something wrong with my if statement?

Benek Lisefski
  • 159
  • 1
  • 3
  • 13
  • After some more testing, I've concluded that my `$(".header a.nav").on("touchstart click", function(e)` is actually running twice, so it's triggering the `openMenu` function and then immediately following it up with another loop through that triggers the `closeMenu` function. How on earth could a single click on the menu icon cause the function to run twice? For clarity, this only happens AFTER a new page is loaded via AJAX. On the initial page load the menu functions perfectly. – Benek Lisefski Jun 05 '19 at 22:24
  • More clarification: the problem only occurs if I use the menu to navigate to the new page that loads via AJAX. In other words, only if the menu is open when the AJAX transition takes place. Yet I can confirm that `closeMenu` is being run as part of my AJAX success function, and the var `menuOpen` is properly reset to `false`. If I navigate to the next page by other means, like a text link within the content, rather than interacting with the menu, then the menu opens and closes just fine on the following page. – Benek Lisefski Jun 05 '19 at 22:30

3 Answers3

0

Since you're already indicating state by adding and removing css classes to body, you could just look for those classes instead of polluting the global space with a variable.

(document.body.classList.contains('menu-open') ? closeMenu : openMenu)()
ray
  • 26,557
  • 5
  • 28
  • 27
  • That's actually how I originally did it, but when this problem arose I moved away from doing it that way in case it was the cause of the problem. Is there a chance that will fix my issue? It seems to me like just a different way to accomplish the same thing? – Benek Lisefski Jun 05 '19 at 03:50
  • Is `menuOpen` declared somewhere? – ray Jun 05 '19 at 04:17
  • Yes near the very top of the document `menuOpen = false;` And for the record, this all works perfectly for opening and closing the menu on initial page load, or if I manually refresh the page. It starts failing only after an AJAX page load. – Benek Lisefski Jun 05 '19 at 04:26
  • Have you set a breakpoint in your nav click handler to inspect the `menuOpen` variable? Is it `undefined` at that point? – ray Jun 05 '19 at 04:32
  • I've been using console.log to spit out `menuOpen` at various points, and it appears to be properly defined as `false` when the menu gets closed as part of AJAX success function. Yet my if statement doesn't behave as expected. Would it run both `closeMenu()` and `openMenu()` if `menuOpen` was undefined? – Benek Lisefski Jun 05 '19 at 04:40
  • No. The way it's written in your question it would run `openMenu`. Is this deployed someplace where I can see it? – ray Jun 05 '19 at 04:52
  • unfortunately, it's not publically visible at this time – Benek Lisefski Jun 05 '19 at 04:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/194470/discussion-between-ray-hatfield-and-benek-lisefski). – ray Jun 05 '19 at 04:55
0

var menuOpen = false;

just put it this at top of your code "var" means it make the variable global

kishan
  • 16
  • 3
  • The var part doesn't make it global, because you're declaring it at the top of your code this puts it in scope of the rest of the code, that's what makes it global. To make a JS variable global, just don't use var - however I wouldn't suggest doing that. Here's more info on using a variable declaration without var: https://stackoverflow.com/a/2485439/833878 Check this out for more info on JS declarations: https://dev.to/sarah_chima/var-let-and-const--whats-the-difference-69e – Robbie Jun 05 '19 at 09:28
  • I already declare the variable and set it to false at the top of my javascript document. – Benek Lisefski Jun 05 '19 at 22:01
0

Found my own solution. The event handler was getting attached multiple times causing the function to run two or more time simultaneously if triggered after an AJAX page load. Added $(".header a.nav").off(); before my $(".header a.nav").on(...); and it works as expected.

Benek Lisefski
  • 159
  • 1
  • 3
  • 13