jquery DataTables parent and child rows posted to server as one record instead of two

那年仲夏 提交于 2019-12-24 08:26:32

问题


I have a problem where jquery DataTables creates parent and child rows on resize (responsive DataTable) and I need to save values of inputs from child rows as well as from parent rows and post via ajax to controller action.

Responsive (resized) DataTable:

Normal (not resized) DataTable:

Currently I am using this jquery function to post data to the server:

$('#SaveItemButton').click(function (e) {       
        var arr = [];       
        var rows = $('#ItemTable').find('tbody').find('tr');
        console.log(rows.length);       
        $.each(rows, function (index, item) {           
            var controls = $(this).find('input, select');    
            console.log(controls.length);            
            item = {
                ItemType: controls.eq(0).val(),
                Unit: controls.eq(1).val(),
                Quantity: controls.eq(2).val(),
                Price: controls.eq(3).val(),
                InvoiceDate: $('#InvoiceDate').val(),
                TransferDate: $('#TransferDate').val(),
                TransferPlace: $('#TransferPlace').val(),
                InvoiceDescription: $('#InvoiceDescription').val()
            };            
            arr.push(item);
        });

        $.ajax({
            url: '/Item/Add',
            data: JSON.stringify(arr),
            contentType: 'application/json',
            type: "POST",
            dataType: "json",
            success: function (result) {
                //alert(result);
            },
            error: function (errormessage) {                

            }
        });  
        return false;
    });

but when the Datatable is resized it returns two rows which in turn gets posted to the server.

I am retrieving rows from a table via:

var rows = $('#ItemTable').find('tbody').find('tr');

How can I get all the related parent rows and child rows as one row so I can post that row to the server?

Parent row example:

<tr role="row" class="odd parent">
    <td tabindex="0" style=""></td>
    <td class="sorting_1"><input name="ItemType" class="form-control" type="text"></td>
    <td style="display: none;"><select name="Unit" class="form-control defaultpicker"><option>dan</option><option>Komad</option><option>Sat</option>m<option>m2</option><option>m3</option><option>kg</option><option>lit</option><option>pak</option><option>reč</option></select></td>
    <td style="display: none;"><input name="Quantity" class="form-control" type="number"></td>
    <td style="display: none;"><input name="Price" class="form-control" type="text"></td>
    <td style="display: none;"><input name="Total" class="form-control" type="text" readonly=""></td>
    <td style="display: none;"><button type="submit" id="DeleteButton" class="fa fa-times select-row btn btn-secondary btn-sm" data-id=""></button>
    </td>
</tr>

Child row example:

<tr class="child">
    <td class="child" colspan="2">
        <ul data-dtr-index="0" class="dtr-details">
            <li data-dtr-index="2" data-dt-row="0" data-dt-column="2">
                <span class="dtr-title">Unit</span>
                <span class="dtr-data">
                    <select name="Unit" class="form-control defaultpicker"><option>dan</option><option>Komad</option><option>Sat</option>m<option>m2</option><option>m3</option><option>kg</option><option>lit</option><option>pak</option><option>reč</option></select>
                </span>
            </li>
            <li data-dtr-index="3" data-dt-row="0" data-dt-column="3">
                <span class="dtr-title">Quantity</span>
                <span class="dtr-data">
                    <input name="Quantity" class="form-control" type="number" value="3">
                </span>
            </li>
            <li data-dtr-index="4" data-dt-row="0" data-dt-column="4">
                <span class="dtr-title">Price</span>
                <span class="dtr-data">
                    <input name="Price" class="form-control" type="text" value="1000">
                </span>
            </li>
            <li data-dtr-index="5" data-dt-row="0" data-dt-column="5">
                <span class="dtr-title">Total</span>
                <span class="dtr-data">
                    <input name="Total" class="form-control" type="text" readonly="" value="">
                </span>
            </li>
            <li data-dtr-index="6" data-dt-row="0" data-dt-column="6">
                <span class="dtr-title"></span>
                <span class="dtr-data">
                    <button type="submit" id="DeleteButton" class="fa fa-times select-row btn btn-secondary btn-sm" data-id=""></button>
                </span>
            </li>
        </ul>
    </td>
</tr>

Controller posted data, index 0 contains valid data:

Code Snippet:

var table = $('#ItemTable').DataTable({
  "dom": '<"toolbar">frtip',
  "paging": true,
  "pagingType": "full_numbers",
  "searching": false,
  // Solution to responsive table losing data
  'columnDefs': [{
    'targets': [1, 2, 3, 4, 5, 6],
    'render': function(data, type, row, meta) {
      if (type === 'display') {
        var api = new $.fn.dataTable.Api(meta.settings);

        var $el = $('input, select, textarea', api.cell({
          row: meta.row,
          column: meta.col
        }).node());

        var $html = $(data).wrap('<div/>').parent();

        if ($el.prop('tagName') === 'INPUT') {
          $('input', $html).attr('value', $el.val());
          if ($el.prop('checked')) {
            $('input', $html).attr('checked', 'checked');
          }
        } else if ($el.prop('tagName') === 'TEXTAREA') {
          $('textarea', $html).html($el.val());

        } else if ($el.prop('tagName') === 'SELECT') {
          $('option:selected', $html).removeAttr('selected');
          $('option', $html).filter(function() {
            return ($(this).attr('value') === $el.val());
          }).attr('selected', 'selected');
        }

        data = $html.html();
      }

      return data;
    }
  }],
  'responsive': true,
  order: [1, 'asc']
});

// Solution to responsive table losing data
$('#ItemTable tbody').on('keyup change', '.child input, .child select, .child textarea', function(e) {
  var $el = $(this);
  var rowIdx = $el.closest('ul').data('dtr-index');
  var colIdx = $el.closest('li').data('dtr-index');
  var cell = table.cell({
    row: rowIdx,
    column: colIdx
  }).node();
  $('input, select, textarea', cell).val($el.val());
  if ($el.is(':checked')) {
    $('input', cell).prop('checked', true);
  } else {
    $('input', cell).removeProp('checked');
  }
});

$('#SaveItemButton').click(function() {
  var arr = [];
  var rows = $('#ItemTable').find('tbody').find('tr');
  console.log(rows.length);
  $.each(rows, function(index, item) {
    var controls = $(this).find('input, select');
    console.log(controls.length);
    item = {
      ItemType: controls.eq(0).val(),
      Unit: controls.eq(1).val(),
      Quantity: controls.eq(2).val(),
      Price: controls.eq(3).val(),
      InvoiceDate: $('#InvoiceDate').val(),
      TransferDate: $('#TransferDate').val(),
      TransferPlace: $('#TransferPlace').val(),
      InvoiceDescription: $('#InvoiceDescription').val()
    };
    arr.push(item);
  });

  $.ajax({
    url: '/Item/Add',
    data: JSON.stringify(arr),
    contentType: 'application/json',
    type: "POST",
    dataType: "json",
    success: function(result) {
      //alert(result);
    },
    error: function(errormessage) {

    }
  });
  return false;
});
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet" />
<link href="https://cdn.datatables.net/responsive/2.2.3/css/responsive.dataTables.min.css" rel="stylesheet" />


<table id="ItemTable" class="table table-hover table-secondary dataTable no-footer dtr-inline" style="width: 100%;" role="grid" aria-describedby="ItemTable_info">
  <thead>
    <tr role="row">
      <th></th>
      <th>ItemType</th>
      <th>Unit</th>
      <th>Quantity</th>
      <th>Price</th>
      <th>Total</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr role="row" class="odd parent">
      <td tabindex="0" style=""></td>
      <td class="sorting_1"><input name="ItemType" class="form-control" type="text"></td>
      <td style="">
        <select name="Unit" class="form-control defaultpicker">
          <option>value1</option>
          <option>value2</option>
          <option>value3</option>
          <option>value4</option>
          <option>value5</option>
          <option>value6</option>
          <option>value7</option>
          <option>value8</option>
          <option>value9</option>
        </select>
      </td>
      <td style=""><input name="Quantity" class="form-control" type="number"></td>
      <td style=""><input name="Price" class="form-control" type="text"></td>
      <td style=""><input name="Total" class="form-control" type="text" readonly=""></td>
      <td style=""><button type="submit" id="DeleteButton" data-id=""></button></td>
    </tr>
  </tbody>
</table>


<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/1.5.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/select/1.2.6/js/dataTables.select.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/dataTables.responsive.min.js"></script>

回答1:


Well, you really cannot. At first DT inject and remove child rows and their content to and from the DOM, making them invisible to simple jQuery selectors. You can target open child rows, but that is all.

Secondly you cannot select multiple elements in pairs. You could have for example $('tr.parent, tr.parent ~ tr.child') or similar, but that would be equal to just $('tr'). I would go through the API:

table.rows().every(function() {
  var $node = this.nodes().to$();
  var item = {
    ItemType: $node.find('input[name=ItemType]').val(),
    Unit: $node.find('select[name=Unit]').val(),
    Quantity: $node.find('input[name=Quantity]').val(),
    Price: $node.find('input[name=Price]').val(),
    Total: $node.find('input[name=Total]').val(),
    InvoiceDate: $('#InvoiceDate').val(),
    TransferDate: $('#TransferDate').val(),
    TransferPlace: $('#TransferPlace').val(),
    InvoiceDescription: $('#InvoiceDescription').val()
  };
  arr.push(item)
})

Completely untested. See JQuery Datatables search within input and select on how to update the DT internals when form controls is changing. Otherwise you will just get return default / original values.



来源:https://stackoverflow.com/questions/52313856/jquery-datatables-parent-and-child-rows-posted-to-server-as-one-record-instead-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!