Search code examples
jquerydatatable

DataTable with clickable TD, display controls on click with hide and update on blur using jQuery


In the datatable columns are filled with values. When I am clicking on TD cell and getting the value of cell but the alert get repeated. But I want it one time only. Also the cell should get display with select option for first 2 columns and input text for another 2 columns with the TD cell value.

Below is the code and I have made an onClick event on each TD to get the value. But how should I make the alert should popup once and to display select option and input box.? Also how should get the controls hide when clicked on outside of datatable?

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet" />
    <link href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css" rel="stylesheet" />

    <script src="https://code.jquery.com/jquery-3.5.1.js" type="text/javascript"></script>
    <script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js" type="text/javascript"></script>
    <script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js" type="text/javascript"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js" type="text/javascript"></script>
    <script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js" type="text/javascript"></script>

    <script>
        $(document).ready(function () {
            $('#example').DataTable();
        });

        function Edit(n) {
            $('.clickable').click(function (e) {
                var val1 = $(this).text();
                alert(val1);
                return;
            });
        }

    </script>
<form id="form1" runat="server">
        <div id="GridView">
            <table id="example" class="display" style="width: 100%">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Position</th>
                        <th>Office</th>
                        <th>Age</th>
                        <th>Start date</th>
                        <th>Salary</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td onclick="Edit('1')" class="clickable">Tiger Nixon</td>
                        <td onclick="Edit('2')" class="clickable">System Architect</td>
                        <td onclick="Edit('3')" class="clickable">Edinburgh</td>
                        <td onclick="Edit('4')" class="clickable">61</td>
                        <td onclick="Edit('5')" class="clickable">2011-04-25</td>
                        <td onclick="Edit('6')" class="clickable">$320,800</td>
                    </tr>
                    <tr>
                        <td onclick="Edit('1')" class="clickable">Garrett Winters</td>
                        <td onclick="Edit('2')" class="clickable">Accountant</td>
                        <td onclick="Edit('3')" class="clickable">Tokyo</td>
                        <td onclick="Edit('4')" class="clickable">63</td>
                        <td onclick="Edit('5')" class="clickable">2011-07-25</td>
                        <td onclick="Edit('6')" class="clickable">$170,750</td>
                    </tr>
                    <tr>
                        <td onclick="Edit('1')" class="clickable">Ashton Cox</td>
                        <td onclick="Edit('2')" class="clickable">Junior Technical Author</td>
                        <td onclick="Edit('3')" class="clickable">San Francisco</td>
                        <td onclick="Edit('4')" class="clickable">66</td>
                        <td onclick="Edit('5')" class="clickable">2009-01-12</td>
                        <td onclick="Edit('6')">$86,000</td>
                    </tr>
                </tbody>
                <tfoot>
                    <tr>
                        <th>Name</th>
                        <th>Position</th>
                        <th>Office</th>
                        <th>Age</th>
                        <th>Start date</th>
                        <th>Salary</th>
                    </tr>
                </tfoot>
            </table>
        </div>
    </form>


Solution

  • This is not a complete answer, because I am not sure what exactly you are trying to achieve (especially regarding the drop-down functionality you mention).

    But maybe this partial answer will point you in the right direction.

    It handles editable cells.

    var my_data = [{
        "id": "123",
        "name": "Tiger Nixon",
        "position": "System Architect",
        "salary": "$320,800",
        "notes": "lorem ipsum",
        "office": "Edinburgh",
        "extn": "5421"
      },
      {
        "id": "456",
        "name": "Donna Snider",
        "position": "Customer Support",
        "salary": "$112,000",
        "notes": "dolor sit amet",
        "office": "New York",
        "extn": "4226"
      }
    ];
    
    $(document).ready(function() {
    
      const originals = new Map(); // tracks edits
    
      var table = $('#example').DataTable({
        data: my_data,
        columns: [{
            title: "ID",
            data: "id"
          },
          {
            title: "Name",
            data: "name"
          },
          {
            title: "Office",
            data: "office"
          },
          {
            title: "Position",
            data: "position"
          },
          {
            title: "Notes",
            data: "notes"
          },
          {
            title: "Extn.",
            data: "extn"
          },
          {
            title: "Salary",
            data: "salary"
          }
        ],
        columnDefs: [{
          targets: [1, 2, 3, 4],
          createdCell: function(td, cellData, rowData, rowIdx, colIdx) {
            td.setAttribute('contenteditable', true);
            td.setAttribute('spellcheck', false);
            td.addEventListener("focus", function(e) {
              originals.set(rowIdx + ':' + colIdx, e.target.textContent);
            });
            td.addEventListener("blur", function(e) {
              if (originals.get(rowIdx + ':' + colIdx) !== e.target.textContent) {
                $('#example').DataTable().cell(rowIdx, colIdx).data(td.innerHTML);
              }
            });
          }
        }]
    
      });
    
    });
    <!doctype html>
    <html>
    
    <head>
      <meta charset="UTF-8">
      <title>Demo</title>
      <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
      <script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
      <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
      <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
    
    </head>
    
    <body>
    
      <div style="margin: 20px;">
    
        <table id="example" class="display dataTable cell-border" style="width:100%">
        </table>
    
      </div>
    
    </body>
    
    </html>

    The Name, Office, Position, and Notes columns are editable. Just click on a cell to edit the contents. Click somewhere else to save the edits.

    The code uses contenteditable to make data editable.

    It uses a map to capture pre-edit values:

    const originals = new Map();
    

    This is just to avoid unnecessary work, if the user doesn't actually make an edit change to a cell.

    The new value provided by the user's edits is saved back to the underlying DataTable using cell().data():

    $('#example').DataTable().cell(rowIdx, colIdx).data(td.innerHTML);
    

    We don't even bother to re-draw the DataTable, after doing this, as the display is already up-to-date.


    Suggestion

    Take the above code and see if it works the way you need.

    Then, if it does, maybe you can see if you can add drop-down logic, in a similar way. You can build a dropdown using the following basic approach:

    var arr = [
      {val : 0, text: ''},
      {val : 1, text: 'Edinburgh'},
      {val : 2, text: 'New York'}
    ];
    var sel = $('<select>').appendTo(td);
    $(arr).each(function() {
      sel.append($("<option>").attr('value',this.val).text(this.text));
    });
    

    Depending on what you actually need, I think there is probably a lot more logic needed - espeically to manage the changes between showing a drop-down and showing a plain (selected) value.

    But I have not tried this (and I'm not sure I would even know how to do it, myself).

    Maybe you can try for yourself and ask a new, specific question, if you run into a new specific problem.