Search code examples
jquerydrop-down-menubootstrap-5

Reusable dropdown using jQuery and Bootstrap


I am trying to build reusable dropdown with latest jQuery 3.6.1 and Bootstrap 5.2.3 but it has proven difficult.

I need to dynamically update the dropdown's links with values from data attributes specified on the button that was clicked.

I am looking at the excellent solution provided by roko-c-buljan but it is using vanilla js and I need jQuery. Below is my code by clicking on the Action buttons "...", I get an error:

{
  "message": "Uncaught TypeError: Cannot read properties of null (reading 'classList')",
  "filename": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.bundle.min.js",
  "lineno": 6,
  "colno": 44054
}

Code

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/css/bootstrap.min.css" integrity="sha512-SbiR/eusphKoMVVXysTKG/7VseWii+Y3FdHrt0EpKgpToZeemhqHeZeLWLhJutz/2ut2Vw1uQEj2MbRF+TVBUA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>
    <table class="table">
        <thead>
            <tr>
                <th>Type</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>item 1</td>
                <td>
                    <div class="dropdown">
                        <button type="button" class="btn btn-primary" data-type="ddbtn" data-id="1"  data-value="some value 1" data-bs-toggle="dropdown" aria-expanded="false" >...</button>
                    </div>
                </td>
            </tr>
            <tr>
                <td>item 2</td>
                <td>
                    <div class="dropdown">
                        <button type="button" class="btn btn-primary" data-type="ddbtn" data-id="2" data-value="some value 2" data-bs-toggle="dropdown" aria-expanded="false" >...</button>
                    </div>
                </td>
            </tr>
        </tbody>
    </table>

    <ul id="contextMenu" class="dropdown-menu">
        <li><a href="#" tabindex="-1" class="dropdown-item" id="link1">Action 1</a></li>
        <li><a href="#" tabindex="-1" class="dropdown-item" id="link2">Action 2</a></li>
    </ul>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.bundle.min.js" integrity="sha512-i9cEfJwUwViEPFKdC1enz4ZRGBj8YQo6QByFTF92YXHi7waCqyexvRD75S5NVTsSiTv7rKWqG9Y5eFxmRsOn0A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
    $(function () {
        $dropdown = $("#contextMenu"); // let's get the dropdown menu
        $("button[data-type='ddbtn']").click(function () {
            var id = $(this).data("id");
            console.log(id);

            $("#link1").attr("href","/action/dosomething?id=" + id);
            $("#link1").text($(this).data("value")); // just for test purposes.
            $("#link2").attr("href","/action/somethingelse?id=" + id);


            $(this).dropdown();
        });
    });
    </script>
</body>
</html>


Solution

  • Try this

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/css/bootstrap.min.css" integrity="sha512-SbiR/eusphKoMVVXysTKG/7VseWii+Y3FdHrt0EpKgpToZeemhqHeZeLWLhJutz/2ut2Vw1uQEj2MbRF+TVBUA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.bundle.min.js" integrity="sha512-i9cEfJwUwViEPFKdC1enz4ZRGBj8YQo6QByFTF92YXHi7waCqyexvRD75S5NVTsSiTv7rKWqG9Y5eFxmRsOn0A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    </head>
    <body>
        <table class="table">
            <thead>
                <tr>
                    <th>Type</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>item 1</td>
                    <td>
                        <div class="dropdown">
                            <button type="button" class="btn btn-primary" data-type="ddbtn" data-id="1"  data-value="some value 1" data-bs-toggle="dropdown" aria-expanded="false" >...</button>
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>item 2</td>
                    <td>
                        <div class="dropdown">
                            <button type="button" class="btn btn-primary" data-type="ddbtn" data-id="2" data-value="some value 2" data-bs-toggle="dropdown" aria-expanded="false" >...</button>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
        <ul id="contextMenu" class="dropdown-menu">
            <li><a href="#" tabindex="-1" class="dropdown-item link1">Action 1</a></li>
            <li><a href="#" tabindex="-1" class="dropdown-item link2">Action 2</a></li>
        </ul>
    
        <script>
        $(function () {
            var $dropdown = $("#contextMenu");
    
            $("button[data-type='ddbtn']").each(function(){
                var id = $(this).data("id");
                var $menu = $dropdown.clone();
    
                $menu.find(".link1").attr("href","/action/dosomething?id=" + id);
                $menu.find(".link1").text($(this).data("value"));
                $menu.find(".link2").attr("href","/action/somethingelse?id=" + id);
                $(this).after($menu);
            });
        });
        </script>
    </body>
    </html>