javascriptjquerydomjquery-eventsjquery-on

Issue with jQuery .on() function on DOM created elements


In my web application I use .on() from jQuery to bind click event to a specific li elements in a dynamic multilevel menu created by an AJAX call and passed to the DOM.

$(".dl-menu li:not(:has(li)):not(.dl-back)").on("click", function(){
  // My Code...
});

Obviously I put this code behind all the dependencies (jQuery in this case), but I does not work, the code is not being executed.

Only works if I open Firebug and paste the code in it.

I also have tried this:

$(document).ready(function() {
  $(".dl-menu li:not(:has(li)):not(.dl-back)").on("click", function(){
    // My Code...
  });
});

But it does not work too.

What I'm doing wrong?

EDIT: To add more details:

HTML structure:

  <div id='tab2' class='col s12'>
    <div class='section no-pad-bot' id='index-banner'>
      <br><br>
      <h2 class='header center green-text'>MENU</h2>
      <div id='prodcontainer'>
        <div id='dl-menu' class='dl-menuwrapper'></div>
      </div>
    </div>
  </div>

AJAX: (the important parte - the code inside success

$(".dl-menuwrapper").html("<button class='dl-trigger' style='visibility:hidden;'></button>"+json.html.replace('dl-submenu', 'dl-menu dl-menuopen'));
$('#dl-menu').dlmenu();

The json.html contains the string with the HTML to being added to the DOM. Like this:

json.html='<ul class="dl-submenu"><li data-id="17"><a href="#" class="catlink">A</a><ul class="dl-submenu"><li data-id="18"><a href="#" class="catlink">B</a><ul class="dl-submenu"><li data-id="20"><a href="#" class="catlink">C</a></li><li data-id="21"><a href="#" class="catlink">D</a></li></ul></li><li data-id="19"><a href="#" class="catlink">E</a></li></ul></li></ul>'

Solution

  • Using .on() this way only binds elements that are currently in the DOM. Because you load the menu through AJAX, it is not available when this code is executed.

    The best workaround is to select a wrapper and specify a selector:

    $(".dl-menu").on("click", "li:not(:has(li)):not(.dl-back)", function(){
    
    });
    

    Providing .dl-menu exists in the HTML that you do not create once the document is loaded.

    EDIT - Alternative

    Place the code setting up the event listener after the menu is loaded.