0

My HTML code:

<div class="side-bar">
    <div class="menu">
        <div class="item"><a id="item1" href="#">Dynamically create submenu here</a></div>
        <div class="item">
            <a id="item2" href="#">Already created submenu here</a>
            <div class="sub-menu">
                <a href="#" class="sub-item">Sub item 1</a>
                <a href="#" class="sub-item">Sub item 2</a>
             </div>
        </div>
    </div>
</div>

My CSS:

.side-bar .menu .item .sub-menu{
    background: rgba(255, 255, 255, 0.1);
    display: none;
}

.side-bar .menu .item .sub-menu a{
    padding-left: 80px;
}

My Jquery:

$(document).ready(function(){
    $('#item2').click(function(){
        $(this).next('.sub-menu').slideToggle();
    });
});

This code works perfectly fine, when I click the #item2 anchor tag, the sub menu opens and closes perfectly. I want to use this same style to a sub menu that I created dynamically and attached to #item1. This is my code:

function get_all_the_values(){
    return $.ajax({
            url: '/php_script.php',
            type: 'POST',
            data: {"input": "get values"}
    });
}
$(document).ready(function(){
     $('#item1').click(function(){
        if(!$(this).next('.sub-menu').is(':visible')){
            (async()=>{
                let response = await get_all_the_values();
                const arr = JSON.parse(response);
                let elem = document.createElement("div");
                elem.className="sub-menu";
                elem.id="id1";
                for(var i=0; i<arr.length; i++){
                    var anchor = document.createElement("a");
                    anchor.className="sub-item";
                    anchor.href="#";
                    anchor.innerText = arr[i];
                    elem.appendChild(anchor);
                }
                document.getElementsByClassName("item")[0].appendChild(elem);
                $(this).next('.sub-menu').slideDown();
              });
         }
         else{
             document.getElementById("id1").remove();
             $(this).next('.sub-menu').slideUp();
         }
     });
});

I have checked my response and it's fetching the correct values from my server. I have given the same class name (sub-menu and sub-item to the submenu and subitems respectively) so that it follows the same style that is written in my css.

But it doesn't work as expected. When I click the #item1 anchor, the sub menu doesn't show, even when the console shows that it's created.

Why is that? The classname is the same, so it should follow the same styles. Where am I going wrong?

  • Does this answer your question? [What is DOM Event delegation?](https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation) – Nico Haase Mar 01 '23 at 11:35
  • More specific for jQuery: https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements – Nico Haase Mar 01 '23 at 11:35
  • I don't see any issue here. You code works in fiddle. https://jsfiddle.net/5ynwa7gr/ – CodeThing Mar 01 '23 at 11:57
  • @CodeThing no it doesn't, did you check there is a difference in both when you hide the sub-items again? – Chris G Mar 01 '23 at 12:09
  • 1
    So that's a different question. The op here asked specifically about sub menu not showing up. There is no mention about style when you hide it. – CodeThing Mar 01 '23 at 12:18
  • There was a mistake in copying my code, what I want is to actually fetch the values from my `php` server and then make a `sub-menu` containing those values. I've updated my post, please check –  Mar 01 '23 at 12:25
  • 1
    That has absolutely nothing to do with the question title then – Chris G Mar 01 '23 at 12:38
  • Have you checked the browser developer tools? You can right click your page and select "Inspect" from the menu (or most browsers hit F12). It has a detailed view which style rule was chosen. If you see a conflict you might have a [CSS Specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) problem. You might have styled for an ID or something else. – Peter Krebs Mar 01 '23 at 12:52

1 Answers1

0

The behavior of the dynamically added .sub-menu is different from that of the static one because you are using different methods to show/hide them.

The static one uses .slideToggle() - which has that nice in/out animation. The dynamic one uses document.getElementById("id1").remove() - which immediately removes it from the DOM without a nice animation. :(

What I would do is use Event Delegation to attach the same sliding behavior to all .sub-menu elements.

$('.menu').on('click', '.item', function() {
  $(this).find('.sub-menu').slideToggle();
});

The only remaining piece to take care of is to ensure we slideToggle() the dynamically created menu immediately once we fetch the data and create it. I have altered your code a little bit. The result is:

$('#item1').click(async function() {
  if ($(this).parent().find('.sub-menu').length === 0) {
    const response = await get_all_the_values();
    const arr = JSON.parse(response);
    let elem = document.createElement("div");
      
    elem.className = "sub-menu";
    elem.id = "id1";
      
    for (var i = 0; i < arr.length; i++) {
      var anchor = document.createElement("a");
      
      anchor.className = "sub-item";
      anchor.href = "#";
      anchor.innerText = arr[i];
      elem.appendChild(anchor);
    }
      
    $(this).parent().append(elem);
    $(this).parent().find('.sub-menu').slideToggle();
  }
});

I have created a fiddle for reference.

76484
  • 8,498
  • 3
  • 19
  • 30