Home > Blockchain >  Reusable dropdown using jQuery and Bootstrap
Reusable dropdown using jQuery and Bootstrap

Time:12-08

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 >
        <thead>
            <tr>
                <th>Type</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>item 1</td>
                <td>
                    <div >
                        <button type="button"  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 >
                        <button type="button"  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" >
        <li><a href="#" tabindex="-1"  id="link1">Action 1</a></li>
        <li><a href="#" tabindex="-1"  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>

CodePudding user response:

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 >
        <thead>
            <tr>
                <th>Type</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>item 1</td>
                <td>
                    <div >
                        <button type="button"  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 >
                        <button type="button"  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" >
        <li><a href="#" tabindex="-1" >Action 1</a></li>
        <li><a href="#" tabindex="-1" >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>

CodePudding user response:

Using the first solutions of this related answer in vanilla JavaScript:
simply assign a "shown.bs.dropdown" handler to every button and use dataset to get the data attribute values. Once you got your data values (by using const {id, value} = elBtn.dataset), use setAttribute() or textContent = to set the appropriate changes to your dropdown's Anchor elements

// DOM utility functions:
const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);

// Task: BS5 Popper fix for single static dropdown menu:
const elDropdown = el('#contextMenu');
const elsBtns = els(".optionsButton");
const elDDLink1 = el("#link1");
const elDDLink2 = el("#link2");

const dropdownList = [...elsBtns].map((elBtn) => {
  const instance = new bootstrap.Dropdown(elBtn);
  instance._menu = elDropdown;

  // Add listener to clicked button calling dropdown,
  // and perform some dynamic changes on the dropdown's anchors:
  elBtn.addEventListener("shown.bs.dropdown", (evt) => {
    const {
      id,
      value
    } = elBtn.dataset;
    elDDLink1.setAttribute("href", "/action/dosomething?id="   id);
    elDDLink1.textContent = value; // just for test purposes.
    elDDLink2.setAttribute("href", "/action/somethingelse?id="   id);
  });

  return instance;
});
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">


<table id="myTable" >
  <thead>
    <tr>
      <th>#</th>
      <th>Document</th>
      <th>Reference</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>General Policies</td>
      <td>GP-01-2022</td>
      <td>
        <div >
          <button type="button"  data-type="ddbtn" data-id="1" data-value="some value 1" data-bs-toggle="dropdown" aria-expanded="false">...</button>
        </div>
      </td>
    </tr>
    <tr>
      <td>2</td>
      <td>Training Material</td>
      <td>GP-02-2022</td>
      <td>
        <div >
          <button type="button"  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" >
  <li><a href="#" tabindex="-1"  id="link1">Action 1</a></li>
  <li><a href="#" tabindex="-1"  id="link2">Action 2</a></li>
</ul>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg OMhuP IlRH9sENBO0LRn5q 8nbTov4 1p" crossorigin="anonymous"></script>

  • Related