I am trying to dynamically create this bootstrap 4 dropdown (see answer by @Gerhard Gotz).
The hard coded list works for me, however, I am trying to dynamically create this list and then populate it.
CSS:
.dropdown-submenu {
position: relative;
}
.dropdown-submenu a::after {
transform: rotate(-90deg);
position: absolute;
right: 6px;
top: .8em;
}
.dropdown-submenu .dropdown-menu {
top: 0;
left: 100%;
margin-left: .1rem;
margin-right: .1rem;
}
HTML:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<div class="collapse navbar-collapse" id="navbarNavDropdown">
</div>
Javascript:
$(document).ready(function () {
var data = [
{
"title": "Home",
"child": null
},
{
"title": "Dropdown link",
"child": [
{
"title": "Action",
"child": null
},
{
"title": "Another Action",
"child": null
},
{
"title": "Submenu",
"child": [{
"title": "Submenu action",
"child": null
},
{
"title": "Another submenu action",
"child": null
},
{
"title": "Subsubmenu",
"child": [{
"title": "Subsubmenu action",
"child": null
},
{
"title": "Another subsubmenu action",
"child": null
}
]
},
{
"title": "Second subsubmenu",
"child": [{
"title": "Subsubmenu action",
"child": null
},
{
"title": "Another subsubmenu action",
"child": null
}]
}
]
}
]
}
];
var list_html = "<ul class='navbar-nav'>";
var li_class = "nav-item";
var a_class = "nav-link";
var a_props = "";
for (var i = 0; i < data.length; i++) {
//if (i == 0)
// li_class += " active";
if (data[i].child != null) {
li_class += " dropdown";
a_class += " dropdown-toggle";
a_props = " data-toggle='dropdown' id='navbarDropdownMenuLink'";
}
list_html += "<li class='" + li_class + "'><a class='" + a_class + "'" + a_props + ">" + data[i].title + "</a>";
if (data[i].child != null) {
list_html += CreateDynamicList(data[i], true);
}
list_html += "</li>";
}
list_html += "</ul>";
console.log(list_html);
$("#navbarNavDropdown").html(list_html);
$('.dropdown-menu-new a.dropdown-toggle').on('click', function (e) {
console.log("here");
console.log($(this));
if (!$(this).next().hasClass('show')) {
$(this).parents('.dropdown-menu-new').first().find('.show').removeClass('show');
}
var $subMenu = $(this).next('.dropdown-menu-new');
$subMenu.toggleClass('show');
$(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function (e) {
$('.dropdown-submenu-new .show').removeClass('show');
});
return false;
});
}); // end document ready
function CreateDynamicList(data, isMainFunction) {
var idText = "";
if (isMainFunction)
idText += " aria-labelledby='navbarDropdownMenuLink'";
var list_html = "<ul class='dropdown-menu-new'" + idText + ">";
//console.log(data);
//console.log(data.child);
if (data.child != null)
for (var i = 0; i < data.child.length; i++) {
//if child has no child then else
if (data.child[i].child == null)
list_html += "<li><a class='dropdown-item'>" + data.child[i].title + "</a></li>";
else
list_html += "<li class='dropdown-submenu-new'><a class='dropdown-item dropdown-toggle'>" + data.child[i].title + "</a>" + (data.child != null ? CreateDynamicList(data.child[i], false) : "") + "</li>";
console.log("loop: " + data.child[i].title);
}
else
list_html += "<li><a class='dropdown-item'>" + data.title + "</a></li>";
list_html += "</ul>";
//console.log(list_html);
return list_html;
}
The list is correctly recreated, however, the show class is not being attached on click event. So, particularly the following code is not working:
$('.dropdown-menu-new a.dropdown-toggle').on('click', function (e) {
console.log("here");
console.log($(this));
if (!$(this).next().hasClass('show')) {
$(this).parents('.dropdown-menu-new').first().find('.show').removeClass('show');
}
var $subMenu = $(this).next('.dropdown-menu-new');
$subMenu.toggleClass('show');
$(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function (e) {
$('.dropdown-submenu-new .show').removeClass('show');
});
return false;
});
Also note, "here" is always console logged on click, but $(this) is not!
2
Answers
Ok so I found the issue with my code was that the first tier was built differently and had different classes. So, while the rest of the code was working as expected but the first one was not (which felt like nothing was working).
Also, my .min file was not being updated for a while as I was updating and checking my code. For this issue, I cleaned and rebuilt my code.
The answers given by both @Phil and @Death-is-the-real-truth are still correct. I have added the following pieces of code to make it work in document.ready function.
You need to use event delegation concept to make your code work.
I have added additional CSS to show you that the code worked.
Working snippet:
Note: instead of
.toggleClass('show')
use.toggleClass('collapse')
to make drop-downs open/close perfectly.