Trying to show buttons under every row in DataTable Bootstrap but can only display them under a specific column instead of whole row

Viewed 502

I am creating a system that manages event expenses.

In this system, one event can have multiple installments of a single payment. What I am trying to do is to show these installments whenever the user hovers its mouse over an event in the Table. (Each row represents one event)

These installments can vary from one to multiple, meaning all events won't have same number of installments.

So, what I did was basically this,

So, if you can see, basically green buttons represent paid installments and yellow warning buttons represent unpaid installments.

but problem is, they are being shown under a single column. I want these to be spread horizontally under that row, rather than being shown under a single column.

Here's a code that I am using to show this datatable, (only including the relevant code)

<style type="text/css">
  #events-table tr .links 
  {
    display:none;
  }
  #events-table tr:hover .links 
  {
    display:block;   
  }
 </style>   
            <!-- Begin Page Content -->
            <div class="container-fluid">

                <!-- Page Heading -->
                <h1 class="h3 mb-4 text-gray-800">Events</h1>

                <div class = "container mb-3 mt-3" id = "events_table">

                </div>

jQuery code

$(document).ready(function(){
        function getEvents() {
            $.ajax ({
                url: "action.php",
                type: "POST", 
                data: {action: "get_events"},
                success: function(response) {
                    $("#events_table").html(response);
                    table = $("table").DataTable({
                        pagingType: 'full_numbers',
                        filter: true, 
                    });
                }
            })
        }

        getEvents(); 
    });

And this is the action.php file, this is where I am writing all the syntax for this table.

if (isset($_POST['action']) && $_POST['action'] == "get_events")
{
    $output = ''; 
    $data = $db->get_all_events(); 
    $output .= '


    <table id = "events-table" class = "table table-striped table-bordered ">
              <thead>
                <tr>
                  <th data-field="id" data-sortable = "true">ID</th>
                  <th data-field="event_name" data-sortable = "true">Event Name</th>
                  <th data-field="date" data-sortable = "true">Date</th>
                  <th data-field="payment" data-sortable = "true">Total Payment</th>
                  <th data-field="expense" data-sortable = "true">Expenses</th>
                  <th data-field="profit" data-sortable = "true">Profit</th>
                  <th data-field="actions" data-sortable = "false">Actions</th>
                </tr>
              </thead>
              <tbody>';
      $number = 1; 
    foreach($data as $row)
    {
        $expense = $row['discount']+$row['photo']+$row['video']; 
        $profit = $row['payment'] - $expense; 
        $date = $row['day'].'-'.$row['month'].'-'.$row['year'];
        $output .= '<tr class ="text-center text-secondary">
        <td>'.$number.'</td>
        <td>'.$row['e_name'].'';

        $payments = $db->get_payments($row['c_id']);
        foreach ($payments as $payment)
        {
          if ($payment['p_status'] == 'pending')
          {
            $output .= '<div class="links" style = "margin-right: 50%; margin-top: 10px;">
            <a id="do_payment" data-id1= '.$payment['p_id'].' class="btn btn-warning btn-icon-split"> <span class="icon text-white-50"> <i class="fas fa-exclamation-triangle"></i> </span> <span class="text">'.$payment['p_amount'].'</span></div>';
          }
          else 
          {
            $output .= '<div class="links" style = "margin-right: 50%; margin-top: 10px;">
            <a id="remove_payment" data-id1= '.$payment['p_id'].' class="btn btn-success btn-icon-split"> <span class="icon text-white-50"> <i class="fas fa-check"></i> </span> <span class="text">'.$payment['p_amount'].'</span></div>';
          }
        }
        $output .='</td>
        <td>'.$date.'</td>
        <td>'.$row['payment'].'</td>
        <td style="color: red">'.$expense.'</td>
        <td style="color: green">'.$profit.'</td>
        <td><a id="view_event" data-id1 = '.$row['c_id'].' class="btn btn-outline-info btn-sm" href="">View</a>
        <a id="update_event" data-id1 = '.$row['c_id'].' class="btn btn-outline-secondary btn-sm" href="">Update</a>
        <a id="delete_event" data-id1 = '.$row['c_id'].' class="btn btn-outline-danger btn-sm" href="">Delete</a></td>
        </tr>';

        $number++;  
    }
    $output .= '</tbody></table>';
    echo $output;
}  

As you would notice, currently I have my buttons set under the "Event Name" field. I would like to have those buttons spread over the whole row. Any help would be really appreciated.

Also, can anyone tell how can I align the Show entries and the Search Bar on top of the table? Thank you.

Edit: I tried to use the colspan property by creating a new row in the table and put my buttons in it (as suggested in comments) but it did not work out for me. Instead, it showed some very undesirable results.

First of all, the buttons did separate from the "one" column, so that issue did get resolved but in this case, now all the similar buttons were in same column still. For example, Green buttons were stacked up upon each other while yellow buttons were separate but stacked up upon each other.

Plus, bigger problem was now the buttons would show only when I "hover" over the row under the "Events" Row. It has a created a very small White Line under each row to represent the buttons row and Buttons get displayed only when I hover over that white line while nothing shows up when I hover over the actual Event Row.

The new modified code of action.php is as follows,

if (isset($_POST['action']) && $_POST['action'] == "get_events")
{
    $output = ''; 
    $data = $db->get_all_events(); 
    $output .= '


    <table id = "events-table" class = "table table-striped table-bordered ">
              <thead>
                <tr>
                  <th data-field="id" data-sortable = "true">ID</th>
                  <th data-field="event_name" data-sortable = "true">Event Name</th>
                  <th data-field="date" data-sortable = "true">Date</th>
                  <th data-field="payment" data-sortable = "true">Total Payment</th>
                  <th data-field="expense" data-sortable = "true">Expenses</th>
                  <th data-field="profit" data-sortable = "true">Profit</th>
                  <th data-field="actions" data-sortable = "false">Actions</th>
                </tr>
              </thead>
              <tbody>';
      $number = 1; 
    foreach($data as $row)
    {
        $expense = $row['discount']+$row['photo']+$row['video']; 
        $profit = $row['payment'] - $expense; 
        $date = $row['day'].'-'.$row['month'].'-'.$row['year'];
        $output .= '<tr class ="text-center text-secondary">
        <td>'.$number.'</td>
        <td>'.$row['e_name'].'';

        
        $output .='</td>
        <td>'.$date.'</td>
        <td>'.$row['payment'].'</td>
        <td style="color: red">Rs. '.$expense.'</td>
        <td style="color: green">Rs. '.$profit.'</td>
        <td><a id="view_event" data-id1 = '.$row['c_id'].' class="btn btn-outline-info btn-sm" href="">View</a>
        <a id="update_event" data-id1 = '.$row['c_id'].' class="btn btn-outline-secondary btn-sm" href="">Update</a>
        <a id="delete_event" data-id1 = '.$row['c_id'].' class="btn btn-outline-danger btn-sm" href="">Delete</a></td>
        </tr>
        <tr><td colspan="5">';
        $payments = $db->get_payments($row['c_id']);
        $output .= '<div class="links">';
        foreach ($payments as $payment)
        {
          if ($payment['p_status'] == 'pending')
          {
            
            $output .='<a id="do_payment" data-id1= '.$payment['p_id'].' class="btn btn-warning btn-icon-split"> <span class="icon text-white-50"> <i class="fas fa-exclamation-triangle"></i> </span> <span class="text">'.$payment['p_amount'].'</span></div>';
          }
          else 
          {
            $output .='<a id="remove_payment" data-id1= '.$payment['p_id'].' class="btn btn-success btn-icon-split"> <span class="icon text-white-50"> <i class="fas fa-check"></i> </span> <span class="text">'.$payment['p_amount'].'</span></div>';
          }
        }
        $output .='</td></tr>';

        $number++;  
    }
    $output .= '</tbody></table>';
    echo $output;
}  
1 Answers

You can use the "child rows" feature of DataTables - see an example here.

The benefit of these child rows is that they span the entire width of the table but only contain one cell.

In your case, you need to make some adjustments:

  1. Make sure every child row is always displayed. As you can see in the above linked demo, they are all hidden by default.

  2. Hide the column which normally contains the "show/hide" button for each child row.

Here is some code showing my simple demo:

// this function controls what is displayed in each child row. It has access to all the parent row's data
function format ( rowData ) {
    // `rowData` is the data object (or array) for the row
    return '<span>Put whatever you want in here, for example: "<b>' + rowData.name + '"</b>. It spans all the columns.</span>';
}

$(document).ready(function() {

  var dataSet = [
    {
      "id": "123",
      "name": "Tiger Nixon",
      "position": "System Architect",
      "salary": "$320,800",
      "start_date": "2011/04/25",
      "office": "Edinburgh",
      "extn": "5421"
    },
    {
      "id": "456",
      "name": "Donna Snider",
      "position": "Customer Support",
      "salary": "$112,000",
      "start_date": "2011/01/25",
      "office": "New York",
      "extn": "4226"
    },
    {
      "id": "567",
      "name": "Cedric Kelly",
      "position": "Senior Javascript Developer",
      "salary": "$433,060",
      "start_date": "2012/03/29",
      "office": "Edinburgh",
      "extn": "6224"
    },
    {
      "id": "432",
      "name": "Airi Satou",
      "position": "Accountant",
      "salary": "$162,700",
      "start_date": "2008/11/28",
      "office": "Tokyo",
      "extn": "5407"
    },
    {
      "id": "987",
      "name": "Brielle Williamson",
      "position": "Integration Specialist",
      "salary": "$372,000",
      "start_date": "2012/12/02",
      "office": "New York",
      "extn": "4804"
    }
  ];


  var table = $('#example').DataTable( {
    data: dataSet,
    columns: [
      {
        "className": 'details-control',
        "orderable": false,
        "data": null,
        "visible": false, // do not show the open/close column
        "defaultContent": ''
      },
      { "data": "name" },
      { "data": "position" },
      { "data": "office" },
      { "data": "salary" }
    ],
    "order": [[1, 'asc']]
  } );

  // force each child row to be displayed:
  $("#example").DataTable().rows().every( function () {
    this.child( format(this.data()) ).show();
    $( this.node() ).addClass('shown');
  });


} );
<!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%">
    <thead>
            <tr>
                <th></th>
                <th>Name</th>
                <th>Position</th>
                <th>Office</th>
                <th>Salary</th>
            </tr>
        </thead>
        <tfoot>
            <tr>
                <th></th>
                <th>Name</th>
                <th>Position</th>
                <th>Office</th>
                <th>Salary</th>
            </tr>
        </tfoot>
    </table>

</div>

</body>
</html>

In the above example, look specifically at the format ( rowData ) function.

In my demo, that function simply assembles some very basic HTML, as a string. That HTML is displayed as the content of the child row.

In your case, you can build much more complex HTML, representing the horizontally-aligned row of buttons you want to display underneath each row.

Related