skip to Main Content

I have a table where clicking anywhere on the row will open a modal dialog (to edit the row) but there are columns that contain links . When those links are clicked on, I don’t want to go to the link and not open the modal.

<body>
<div class="container-fluid">
    <table class="table table-sm table-striped table-bordered table-hover">
        <thead>
        <tr>
            <th>#</th><th>Link</th><th>Date</th>
        </tr>
        </thead>
        <tbody>
        <tr style="cursor:pointer;" role="button" data-bs-toggle="modal" data-bs-target="#myModal">
            <td>1</td><td><a href="https://google.com" target="_blank">go to google</a></td><td>2024-05-18</td>
        </tr>
        </tbody>
    </table>
</div>
<div class="modal fade" id="myModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content border">
            <div class="modal-header px-card bg-light border-bottom-0 p-1">
                <h5 class="modal-title">Modal</h5>
                <button class="btn-close me-n1" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body p-card">
                <p>Here's some stuff</p>
            </div>
            <div class="card-footer d-flex justify-content-end align-items-center bg-light">
                <button class="btn btn-primary px-4" type="button" data-bs-dismiss="modal">Save</button>
            </div>
        </div>
    </div>
</div>
</body>

I’ve tried stopping propagation in the onclick for the href, but it gets called after the show.bs.modal is called so doesn’t help me. I can add an event listener for show.bs.modal, and was hoping to get the href element that was clicked so I could determine if it should be ignored or not, but the relatedTarget is the row, so that doesn’t help me.

Am I going about this the wrong? How do I achieve the results that I’m looking for?

2

Answers


  1. You can create a modal with JavaScript instead of using data-bs-toggle="modal" and data-bs-target="#myModal" attributes.

    1. Remove those attributes.
    2. Add some new identifier to tr instead. Let’s decide we’ve added data-modal-toggle="myModal". This can be used to select trigger elements and get the corresponding modal id.
    3. Create a modal using JavaScript code and add event listener to toggle it on click.
    // select all modal-trigger elements by using the proper selector
    document.querySelectorAll('[data-modal-toggle]').forEach((trigger) => {
      // get modal id from data-modal-toggle value
      const modalId = trigger.dataset.modalToggle;
    
      // create modal instance
      const modal = new bootstrap.Modal(document.getElementById(modalId));
    
      // add event listener to the modal-trigger element
      trigger.addEventListener('click', (e) => {
        // if it isn't 'a' element, then open the modal
        if (e.target.tagName.toLowerCase() !== 'a') {
          modal.toggle();
        }
      });
    });
    
    Login or Signup to reply.
  2. A Simple Solution

    There are multiple possible solutions to this problem. However, a custom attribute that allows you to selectively disable the modal on certain elements is simple to implement. It also continues to work even as rows are dynamically added or deleted.

    Code

    addEventListener('click', (e) => {
      if ('stopPropagation' in e.target.dataset) {
        e.stopPropagation();
      }
    }, true)
    

    Usage

    <a data-stop-propagation href="https://example.com" target="_blank">Link</a>
    

    Demo

    Snippet security prevents opening popups and so a message is logged instead. See the JSFiddle version without this limitation.

    addEventListener('click', (e) => {
      if ('stopPropagation' in e.target.dataset) {
        e.stopPropagation();
        console.log('Link clicked');
      }
    }, true)
    <div class="container-fluid">
      <table class="table table-sm table-striped table-bordered table-hover">
        <thead>
          <tr>
            <th>#</th>
            <th>Link</th>
            <th>Date</th>
          </tr>
        </thead>
        <tbody>
          <tr style="cursor:pointer;" role="button" data-bs-toggle="modal" data-bs-target="#myModal">
            <td>1</td>
            <td><a data-stop-propagation href="https://example.com/" target="example">Link with attribute</a></td>
            <td>2024-05-18</td>
          </tr>
          <tr style="cursor:pointer;" role="button" data-bs-toggle="modal" data-bs-target="#myModal">
            <td>2</td>
            <td><a href="https://example.com/" target="example">Link without attribute</a></td>
            <td>2024-05-19</td>
          </tr>
        </tbody>
      </table>
    </div>
    <div class="modal fade" id="myModal" tabindex="-1">
      <div class="modal-dialog">
        <div class="modal-content border">
          <div class="modal-header px-card bg-light border-bottom-0 p-1">
            <h5 class="modal-title">Modal</h5>
            <button class="btn-close me-n1" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body p-card">
            <p>Here's some stuff</p>
          </div>
          <div class="card-footer d-flex justify-content-end align-items-center bg-light">
            <button class="btn btn-primary px-4" type="button" data-bs-dismiss="modal">Save</button>
          </div>
        </div>
      </div>
    </div>
    
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search