简体   繁体   中英

Jquery how to use this in a event datatable generated td row

I am trying to add a function call "onblur" where i can type a new value in the TD cell. What I need is the new value to be passes by the function to a other Jquery script. My problem is that the datatable wont see the This value as it seems the code is not written correctly. What am I doing wrong? I cant find anything that helped me so far..

This is the php version that works, this is what I am trying to implent in the Datatable table.

<td
    contenteditable="true"
    data-old_value="name"
    onBlur="saveInlineEdit(this,'name','23')"
    onClick="highlightEdit(this);"
>
    name
</td>

Concrete. How do i use the new typed value as "this" in the folowing line, or how do i implement the code that works in the HTML table in the jQuery DataTable?

var options = {
    data: 'my_data',
    render: function ( data, type, row, meta ) {
        return '<div onBlur="saveInlineEdit('this.innerHTML,'name', + row.data_id + ') " onClick="highlightEdit(this);"><font color='+row.cat_color+'>'+data+'</font></div>';
    }
}

The part in the DataTables script to add the attributes:

createdRow: function (row, data, dataIndex) {
    $('td:eq(4)',row).attr('contenteditable',true);
    $('td:eq(4)',row).attr('data-old_value', data.bullets);
}

I want to use the following script to post the value of the saveInlineEdit function

function highlightEdit(editableObj) {
    $(editableObj).css("background","");
} 

function saveInlineEdit(editableObj,column,id) {
    // no change change made then return false
    if($(editableObj).attr('data-old_value') === editableObj.innerHTML) {
        return false;
    }
    // send ajax to update value
    $(editableObj).css("background","#FFF url(loader.gif) no-repeat right");
    $.ajax({
        url: "update_inlinedata.php",
        cache: false,
        data:'column='+column+'&value='+editableObj.innerHTML+'&id='+id,
        success: function(response)  {
            console.log(response);
            // set updated value as old value
            $(editableObj).attr('data-old_value',editableObj.innerHTML);
            $(editableObj).css("background","");            
        }
    });
}

There are a couple of different pieces to your question - the following covers the capturing of changed cell data, and making sure the DataTable reflects the edits made in the DOM by the user.

(I did not tackle the highlighting, but I think you can extend the below approach to cover that as well, since it's handling the same data.)

I think using a createdCell option in a columnDef may be a bit easier than using a createdRow , because you will get direct access to the column's value:

columnDefs: [ {
targets: 4,
createdCell: function (td, cellData, rowData, rowIdx, colIdx) {
  // 'td' is the DOM node, not the DataTable cell
  td.setAttribute('contenteditable', true);
  td.setAttribute('spellcheck', false);
  td.setAttribute('data-old_value', cellData);
  td.addEventListener("focus", function(e) {
    original = e.target.textContent;
  })
  td.addEventListener("blur", function(e) {
    if (original !== e.target.textContent) {
      console.log( 'row ID: ', rowData.id );
      console.log( 'new DOM value: ', td.innerHTML);
      // 'cell' is the DataTable cell, not the DOM node:
      let cell = $('#example').DataTable().cell(rowIdx, colIdx);
      console.log( 'before cell update: ', cell.data() );
      cell.data(td.innerHTML);
      console.log( 'after cell update: ', cell.data() );
    }
  })
}
} ]

Acknowledgement : The above approach is modified from the one shown in this answer .

Here is a self-contained demo:

 var my_data = [ { "id": "123", "name": "Tiger Nixon", "position": "System Architect", "salary": "$320,800", "bullets": "lorem ipsum", "office": "Edinburgh", "extn": "5421" }, { "id": "456", "name": "Donna Snider", "position": "Customer Support", "salary": "$112,000", "bullets": "dolor sit amet", "office": "New York", "extn": "4226" } ]; $(document).ready(function() { 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: "Bullets", data: "bullets" }, { title: "Extn.", data: "extn" }, { title: "Salary", data: "salary" } ], columnDefs: [ { targets: 4, createdCell: function (td, cellData, rowData, rowIdx, colIdx) { // 'td' is the DOM node, not the DataTable cell td.setAttribute('contenteditable', true); td.setAttribute('spellcheck', false); td.setAttribute('data-old_value', cellData); td.addEventListener("focus", function(e) { original = e.target.textContent; }) td.addEventListener("blur", function(e) { if (original.== e.target.textContent) { console:log( 'row ID, '. rowData;id ). console:log( 'new DOM value, '. td;innerHTML), // 'cell' is the DataTable cell: not the DOM node. let cell = $('#example').DataTable(),cell(rowIdx; colIdx). console:log( 'before cell update, '. cell;data() ). cell.data(td;innerHTML). console:log( 'after cell update, '. cell;data() ); } }) } } ] } ); } );
 <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>


Update

I don't have a server which can handle your ajax call, so I cannot test a "success" response. Having said that, here are my notes:

For the saveInlineEdit function, you will no longer need this:

if($(editableObj).attr('data-old_value') === editableObj.innerHTML) {
  return false;
}

This is because you have already performed that check in the event listener:

if (original !== e.target.textContent) { ... }

Also, you have already determined what the new value of the cell is - so you might as well just pass that directly to the function:

saveInlineEdit(td, 'bullets', rowData.id, cell.data());

The above line needs to be placed in the event listener shown above:

td.addEventListener("blur", function(e) {
  if (original !== e.target.textContent) {
    console.log( 'row ', rowIdx, ' col ', colIdx );
    console.log( 'row ID: ', rowData.id );
    console.log( 'new DOM value: ', td.innerHTML);
    // 'cell' is the DataTable cell, not the DOM node:
    let cell = $('#example').DataTable().cell(rowIdx, colIdx);
    console.log( 'before cell update: ', cell.data() );
    cell.data(td.innerHTML);
    console.log( 'after cell update: ', cell.data() );
    let columnName = $('#example').DataTable().settings();
    console.log( 'column name: ', columnName );

    saveInlineEdit(td, 'bullets', rowData.id, cell.data()); // NEW LINE HERE
  }
})

Your saveInlineEdit function therefore changes, to reflect the above points:

I removed the unnecessary if condition.

I added an extra parameter newValue - since we don;t need to keep retrieving it from the cell (we've already done that).

function saveInlineEdit(editableObj, column, id, newValue) {
  console.log( 'in ajax call' );
  console.log(editableObj);
  console.log(column);
  console.log(id);
  console.log(newValue);
  // send ajax to update value
  $(editableObj).css("background","#FFF url(loader.gif) no-repeat right");
  $.ajax({
    url: "update_inlinedata.php",
    cache: false,
    data:'column=' + column + '&value=' + newValue + '&id=' + id,
    success: function(response)  {
      console.log(response);
      // set updated value as old value
      $(editableObj).attr('data-old_value', newValue);
      $(editableObj).css("background","");            
    }
  });
}

I put logging statements into the function, so you can see what the parameters are.

So, for example, the query parameter data submitted by the ajax call will be:

column=bullet&value=lorem%20ipsum%20editedbyme&id=123

And just to say again, I cannot test this ajax call - so bear that in mind, i case I made a stupid mistake there, somewhere.


That leaves 2 additional point which are outside the scope of the question, but which need to be considered:

  1. The question assumes only column index 4 is editable. If you want every cell in a row to be editable you need to enhance this to use the relevant column names. One good way to do this is to use the DataTables name option:

    { title: "Bullets", data: "bullets", name: "bullets" },

This value can be retrieved and used by the blur event handler, before you call your saveInlineEdit function:

let columnName = $('#example').DataTable().settings()[0].aoColumns[colIdx].sName;

Then your call becomes:

saveInlineEdit(td, columnName, rowData.id, cell.data());
  1. The current code updates the data in the DataTable here:

    cell.data(td.innerHTML);

This happens before the return from the ajax call. If that call fails then you have updated data in your data table, but not in the back end database. So you may want to move that logic around to ensure the DataTable data is updated only in the event of a successful ajax call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM