Tabulator add a new row and edit content - javascript

I have following Tabulator setup:
var table = new Tabulator("#data-table", {
layout: "fitColumns", //fit columns to width of table
columns: [ //Define Table Columns
{ title: "Name", field: "name", editor:"input" },
{ title: "IP", field: "ip" },
],
index:"name"
});
Also, I register a function to insert a new row:
function insertRow(){
table.addData([{
name: "",
ip: "",
}], true).then(function(rows){
if (rows.length == 0) return;
rows[0].getCell("name").edit();
})
}
When I call the function insertRow(), it can insert a new row into the table but not open editing for the first cell.
However, following code works:
if (rows.length == 0) return;
setTimeout(function(){
rows[0].getCell("name").edit();
}, 100);
In the documentation http://tabulator.info/docs/4.9/update,
The addData method returns a promise, this can be used to run any
other commands that have to be run after the data has been loaded into
the table. By running them in the promise you ensure they are only run
after the table has loaded the data.
So, it seem that we cannot call rows[0].getCell("name").edit() immediately inside the promise.
Is this correct?
Is there any problem with my code?

If you are only adding one row, use the addRow function instead of the addData function:
table.addRow({name: "", ip: ""], true)
.then(function(row){
rows.getCell("name").edit();
});

Related

how to destroy table and reinitialize same table with new updated data using Datatables Jquery plugin

I am using Datatables plugin and dynmically populating the table with the data returned from server. on different table draws the returned data has variable no of columns. On each table intilization the code is checking if there has been previous initializations and removes it before creating a new table with dynamic data, using this code:
if ( $.fn.dataTable.isDataTable( '#contracts_forecast' ) ) {
$('#contracts_forecast').DataTable().clear();
$('#contracts_forecast').DataTable().destroy();
$('#contracts_forecast tbody').empty();
$('#contracts_forecast thead').empty();
}
On the serverside I am manually editing the data and updating the database. When the database is updated with new data , I want to refresh the table so the change is reflected in the table. In order to do that I am using an POST SUBMIT event, which is triggered after the data is submitted to server and then call the function getDT(filter_product_code, filter_product_name) to update the table with new data
PROBLEM:
When the post submit event is triggered , it recalls the function getDT(filter_product_code, filter_product_name); and change is reflected. BUT THE NEW TABLE with UPDATED IS ADDED TO CURRENT TABLE WITHOUT THE OLD TABLE BEING DESTROYED Which leaves me with two same tables on screen
p.s I am assuming every time getDT() function is called it should check for if table is initialized and destroy it before creating a new one using the same
$(document).ready(function() {
$('#filter').click(function(){
var filter_product_code = $('#filter_product_code').val();
var filter_product_name = $('#filter_product_name').val();
if(filter_product_code == '' || filter_product_name == '')
{
alert('Select Both filter option');
}
var columns = [];
getDT(filter_product_code, filter_product_name);
function getDT(filter_product_code, filter_product_name) {
$.ajax({
serverSide: true,
type:'POST',
url: "/XXX/_fetch.php",
data: {filter_product_code: JSON.stringify(filter_product_code),
filter_product_name: JSON.stringify(filter_product_name)},
success: function (data) {
data = JSON.parse(data);
columnNames = Object.keys(data.data[0]);
for (var i in columnNames) {
columns.push({data: columnNames[i],
title: capitalizeFirstLetter(columnNames[i])});
}
if ( $.fn.dataTable.isDataTable( '#contracts_forecast' ) ) {
$('#contracts_forecast').DataTable().clear();
$('#contracts_forecast').DataTable().destroy();
$('#contracts_forecast tbody').empty();
$('#contracts_forecast thead').empty();
}
table = $('#contracts_forecast').DataTable({
data: data.data,
columns: columns,
dom: "Bfrtip",
select: true,
buttons: [
{ extend: "create", editor: editor },
{ extend: "edit", editor: editor },
{ extend: "remove", editor: editor }
],
"columnDefs": [
{
"targets": [0],
"visible": false,
"searchable": false
},
{ className: "tablecolumns", targets: "_all" },
]
} );
$('#contracts_forecast').on( 'click', 'tbody td:not(:first-child)', function (e) {
editor.inline( this );
} );
}
});
editor.on( 'postSubmit', function ( e, json, data, action, xhr ) {
getDT(filter_product_code, filter_product_name);
});
}
});
} );
I was doing a mistake by declaring the column variable outside function. Each time the function was called it was adding to already existing columns. So just needed to define column variable inside function.
getDT(filter_product_code, filter_product_name);
function getDT(filter_product_code, filter_product_name) {
var columns = [];
$.ajax({
serverSide: true,
// paging: true,
// retrieve:true,
type:'POST',

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:
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());
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.

Is there a way to pull from multiple SQL tables for one DataTables table?

I use DataTables to present data in a reporting website that I created. I am working on creating a Report Builder where users can select multiple tables and then columns from those tables for a custom report.
What I want to know is whether there's a way to do this with DataTables. I'm able to get the tables names and column names for the custom report, but I've not been able to figure out how to send it to DataTables. I currently use server side processing and send an ajax call using POST to the DataTable.
I know that I can program in a SQL query based on the selected tables and columns, but I cannot seem to figure out how to have the data sent to DataTables.
Here is how I initialize my DataTables:
$(document).ready(function ()
{
// Setup - add a text input to each footer cell
$('#DataTable tfoot th').each(function () //creates the search bar as the footer
{
var title = $(this).text();
$(this).html('<input type="text" placeholder="Search ' + title + '" />');
});
var table = $('#DataTable').DataTable({
"lengthMenu": [[25, 50, 75, 100, 150, -1], [25, 50, 75, 100, 150, 'All']],
"dom": '<"top"Bifpl<"clear">>rt<"bottom"ip<"clear">>',
"buttons": [{
extend: 'collection',
text: 'Export',
buttons: ['export', { extend: 'csv',
text: 'Export All To CSV', //Export all to CSV file
action: function (e, dt, node, config)
{
window.location.href = './ServerSide.php?ExportToCSV=Yes';
}
}, 'csv', 'pdf', { extend: 'excel',
text: 'Export Current Page', //Export to Excel only the current page and highlight the first row as headers
exportOptions: {
modifier: {
page: 'current'
}
},
customize: function (xlsx)
{
var sheet = xlsx.xl.worksheets['sheet1.xml'];
$('row:first c', sheet).attr('s', '7');
}
}]
}
],
"fixedHeader": { //Keeps the header and footer visiable at all times
header: true,
footer: true
},
"select": true, //sets the ability to select rows
"processing": true, //shows the "Processing" when working
"serverSide": true, //sends data to the server for processing
"ajax": { //where the data is sent and processed
"url": "./ServerSide.php",
"type": "POST"
},
stateSave: true, //Saves the current state of the page
columnDefs: [{ visible: false, targets: 0}], //Hides the first column the ID column
initComplete: function () //sets the search
{
var api = this.api();
// Apply the search
api.columns().every(function ()
{
var that = this;
$('input', this.footer()).on('keyup change', function (e)
{
if (that.search() !== this.value & e.keyCode == 13) //you have to hit enter for the search to start
{
that
.search(this.value)
.draw();
}
});
});
}
});
});
$.fn.dataTable.ext.buttons.export =
{
className: 'buttons-alert', //Adds the "Export all to Excel" button
id: 'ExportButton',
text: "Export All To Excel",
action: function (e, dt, node, config)
{
window.location.href = './ServerSide.php?ExportToExcel=Yes';
}
};
Here is what I can currently get to work:
I'm not sure else anyone would need to help me with this, but if I'm missing something let me know and I'll add it.
I need all the data from all selected tables and columns to be in one DataTables table presented on the website. In the image above I'm showing that I've gotten as far as getting the column headers and using aliases for the tables. I'm working through my FilterSort.class.pph file (which is like the ssp.class.php in DataTables) to see if I can get it to present the table.
I figured it out. I was still calling the correct DataTables functions, but I wasn't passing the data to the functions. I ended up having to update my ServerSide.php file and my FilterSort.class.php file. Those are the ones that all of the other reports use to send data from the server to the screen. After some trial and error, I got it to work and didn't need to change anything in the code posted in my question.

Saving Only the changed record on a BackGrid grid?

I am in the process of learning Backbone.js and using BackGrid to render data and provide the end user a way to edit records on an Microsoft MVC website. For the purposes of this test grid I am using a Vendor model. The BackGrid makes the data editable by default (which is good for my purpose). I have added the following JavaScript to my view.
var Vendor = Backbone.Model.extend({
initialize: function () {
Backbone.Model.prototype.initialize.apply(this, arguments);
this.on("change", function (model, options) {
if (options && options.save === false) return;
model.url = "/Vendor/BackGridSave";
model.save();
});
}
});
var PageableVendors = Backbone.PageableCollection.extend(
{
model: Vendor,
url: "/Vendor/IndexJson",
state: {
pageSize: 3
},
mode: "client" // page entirely on the client side.
});
var pageableVendors = new PageableVendors();
//{ data: "ID" },
//{ data: "ClientID" },
//{ data: "CarrierID" },
//{ data: "Number" },
//{ data: "Name" },
//{ data: "IsActive" }
var columns = [
{
name: "ID", // The key of the model attribute
label: "ID", // The name to display in the header
editable: false, // By default every cell in a column is editable, but *ID* shouldn't be
// Defines a cell type, and ID is displayed as an integer without the ',' separating 1000s.
cell: Backgrid.IntegerCell.extend({
orderSeparator: ''
})
}, {
name: "ClientID",
label: "ClientID",
cell: "integer" // An integer cell is a number cell that displays humanized integers
}, {
name: "CarrierID",
label: "CarrierID",
cell: "number" // A cell type for floating point value, defaults to have a precision 2 decimal numbers
}, {
name: "Number",
label: "Number",
cell: "string"
}, {
name: "Name",
label: "Name",
cell: "string"
},
{
name: "IsActive",
label: "IsActive",
cell: "boolean"
}
];
// initialize a new grid instance.
var pageableGrid = new Backgrid.Grid({
columns: [
{
name:"",
cell: "select-row",
headercell: "select-all"
}].concat(columns),
collection: pageableVendors
});
// render the grid.
var $p = $("#vendor-grid").append(pageableGrid.render().el);
// Initialize the paginator
var paginator = new Backgrid.Extension.Paginator({
collection: pageableVendors
});
// Render the paginator
$p.after(paginator.render().el);
// Initialize a client-side filter to filter on the client
// mode pageable collection's cache.
var filter = new Backgrid.Extension.ClientSideFilter({
collection: pageableVendors,
fields: ['Name']
});
// REnder the filter.
$p.before(filter.render().el);
//Add some space to the filter and move it to teh right.
$(filter.el).css({ float: "right", margin: "20px" });
// Fetch some data
pageableVendors.fetch({ reset: true });
#{
ViewBag.Title = "BackGridIndex";
}
<h2>BackGridIndex</h2>
<div id="vendor-grid"></div>
#section styles {
#Styles.Render("~/Scripts/backgrid.css")
#Styles.Render("~/Scripts/backgrid-select-all.min.css")
#Styles.Render("~/Scripts/backgrid-filter.min.css")
#Styles.Render("~/Scripts/backgrid-paginator.min.css")
}
#section scripts {
#Scripts.Render("~/Scripts/underscore.min.js")
#Scripts.Render("~/Scripts/backbone.min.js")
#Scripts.Render("~/Scripts/backgrid.js")
#Scripts.Render("~/Scripts/backgrid-select-all.min.js")
#Scripts.Render("~/Scripts/backbone.paginator.min.js")
#Scripts.Render("~/Scripts/backgrid-paginator.min.js")
#Scripts.Render("~/Scripts/backgrid-filter.min.js")
#Scripts.Render("~/Scripts/Robbys/BackGridIndex.js")
}
When the user edits a row, it successfully fires the hits the model.Save() method and passes the model to the save Action, in this case BackGridSave and it successfully saves the record that changed, but seems to save all of the vendors in model when only one of the vendors changed. Is there a way from the JavaScript/Backbone.js/BackGrid to only pass one Vendor - the vendor that changed?
Update: I realized that it is not sending every vendor, but it is sending the same vendor multiple times as though the change event was firing multiple times.
I guess I answered my own question. Well, at least I am getting the desired result. I just added a call to off after the first on. Seems like this would not be necessary though.
var Vendor = Backbone.Model.extend({
initialize: function () {
Backbone.Model.prototype.initialize.apply(this, arguments);
this.on("change", function (model, options) {
if (options && options.save === false) return;
model.url = "/Robbys/BackGridSave";
model.save();
model.off("change", null, this); // prevent the change event from being triggered many times.
});
}
});

How to auto refresh table contents in EXT.js

I'm having a table whose contents(name and status) i'm trying to refresh every 1 min in such a way that the status should change from 'schedule' to 'active' to 'running' w/o having user manually refresh it.
here is the js:
$cls.superclass.constructor.call(this, Ext.apply({
useTemplate: true,
directFn: Service('getRecordService').getRecord,
fields: [
{
name : 'name',
column: {
header: "Name",
renderer: function (record) {
return name(record.data.name);
},
}
},
{
name : 'status',
column: {
header: "status",
renderer: function (record) {
return status(record.data.status);
},
}
},
],
viewConfig: {
getRecord: function (){
///get single record info
}
};
});
I'm not sure how can i write a function in the above snippet that will allow me to auto refresh the table contents every 1 min. Any ideas would be appreciated!
Thanks!
You should take a look at Ext.util.TaskRunner and the singleton Ext.TaskMgr.
It provides methods to start/stop task functions which are executed in a configurable interval.
With that you could try something like below.
var grid = ; // your grid instance
var store = grid.getStore(); // store of your grid, you want to reload
var refreshTask = { // task which reloads the store each minute
run: function() {
store.reload();
},
interval: 60 * 1000 // 1 Minute
};
Ext.util.TaskRunner.start(refreshTask);

Categories

Resources