DataTables row.add() based on columns - datatables

I have a table:
<table class="table table-bordered table-hover" id="user-table">
<thead>
<tr>
<th data-field="id">Id</th>
<th data-field="name">Name</th>
<th data-field="email">Email</th>
<th data-field="company">Company</th>
<th data-field="actions">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>John Doe</td>
<td>john#doe.com</td>
<td>Doe Inc.</td>
<td>
<div class="btn-group">
<i class="fa fa-pencil"></i>
</div>
</td>
</tr>
</tbody>
</table>
My current way to add row:
var columns = $.map(data,function(v,k){
return v;
});
var rowNode = table.row.add(columns).order([0, 'desc']).draw(false).node();
$(rowNode).addClass('selected');
setTimeout(function(){$(rowNode).removeClass('selected');}, 2000);
My data looks like this:
{
"data":[ {
"id": 2,
"name": "Jane Doe",
"email": "jane#doe.com",
"company": "Doe Inc."
}
]
}
Is there a way to add row based on columns? Instead of returning v on a mapped data, I can directly insert data[0] using row.add(). I've been searching but can't get the exact scenario.
Apparently, the purpose is for shuffled data. In a table that have 15 columns, I don't have to worry about the proper column arrangements.
I found this https://datatables.net/reference/api/row.add() example #1 but obviously the documentation says:
Data to use for the new row. This may be an array, object, Javascript object instance or a tr element. If a data structure is used (i.e. array or object) it must be in the same format as the other data in the table (i.e. if your table uses objects, pass in an object with the same properties here!).

If you specify columns (or columnDefs) with data attributes, you can add row or rows in JSON / object literal format:
columns: [
{ data: 'id' },
{ data: 'name' },
{ data: 'email' },
{ data: 'company' }
]
You must also specify the last column, even it is not targeting any data. You can use render(), createdCell() or defaultContent:
const actions = `
<div class="btn-group">
<i class="fa fa-pencil"></i>
</div>
`;
var table = $('#user-table').DataTable({
columns: [
{ data: 'id' },
{ data: 'name' },
{ data: 'email' },
{ data: 'company' },
{ data: null, defaultContent: actions }
]
...
})
Now you can insert data from above:
var rowNode = table.row.add(data.data[0]).order([0, 'desc']).draw(false).node();
or all rows :
table.rows.add(data.data).draw()

Related

Update Export-Data on DataTable [duplicate]

I've been struggling with this code. I need to avoid specific columns from being exported. I have done that but I don't know how to export the text inside any input element.
Here is the code:
$("#campaignMaterialsTable table").DataTable({
dom: 'Bfrtip',
buttons: [
{
extend: 'excel',
className: 'export-button',
text: 'Export as Excel',
columns: ':not(.notexport)',
//exportOptions: {
// format: {
// body: function (data, row, column, node) {
// //
// //check if type is input using jquery
// return $(data).is("input") ?
// $(data).val() :
// data;
// },
// columns: ':not(.notexport)'
// }
//},
title: 'Campaign Materials'
}]
});
I don't know here to put the code at the right place.. while initializing..
I referred to this links, but still not getting what I want:
https://datatables.net/forums/discussion/50724/export-values-typed-in-input-box-excelhtml5
https://datatables.net/forums/discussion/42205/export-data-with-text-box-in-td-of-data-table#latest
https://datatables.net/extensions/buttons/examples/html5/outputFormat-function.html
https://datatables.net/forums/discussion/50724/export-values-typed-in-input-box-excelhtml5
I assume you have a DataTable containing one or more input fields, something like this:
The user can type values into the input fields.
You want to export data to Excel, so that the result looks like this:
Here we can see the user-provided data as well as the standard table data.
To achieve this, I used the following table data:
<table id="example" class="display nowrap dataTable cell-border" 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>Adélaïde Nixon</td>
<td>System Architect</td>
<td><input type="text" id="office" name="office"></td>
<td>432434</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
<tr>
<td>John Smith</td>
<td>Maager</td>
<td><input type="text" id="office" name="office"></td>
<td>6123</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
<tr>
<td>John Smith 2</td>
<td>Director</td>
<td><input type="text" id="office" name="office"></td>
<td>6123</td>
<td>2011/04/25</td>
<td>$320,800</td>
</tr>
</tbody>
</table>
And I used the following DataTable initialization code:
<script type="text/javascript">
$(document).ready(function() {
$('#example').DataTable({
dom: 'Bfrtip',
buttons: [
{
extend: 'excel',
exportOptions: {
format: {
body: function ( inner, rowidx, colidx, node ) {
if ($(node).children("input").length > 0) {
return $(node).children("input").first().val();
} else {
return inner;
}
}
}
}
}
]
});
});
</script>
The body function assumes that, for input fields, there is only an input field in the cell (i.e. the input field is not contained in a form or any other element).
It uses the node parameter to check for input data, to avoid data formatting issues that could occur (e.g. with dates). I recommend doing that rather than using $(data).is("input").
If there is no input field found in the cell, then the cell contents (inner) are returned.
If the structure of your table does not match these assumptions, then you may need to adjust the above code, of course.
Edit
Regarding the follow-up question about choosing which columns to export, there are various ways.
You can hard-code the column indexes you want to export (where index 0 means the first column). For example:
exportOptions: {
columns: [ 0, 1, 2, 3, 5 ],
format: {
body: function ( inner, rowidx, colidx, node ) {
if ($(node).children("input").length > 0) {
return $(node).children("input").first().val();
} else {
return inner;
}
}
}
}
This exports all columns apart from the Start Date column (index 4).
Or you can use the approach in your question, based on a class, I believe. I have not actually tried that one.
Take note of where the columns: [ 0, 1, 2, 3, 5 ] directive is placed - it is inside the exportOptions section.
you can use
exportOptions:{
columns: ':visible'
}
in below buttons
buttons: [
{
extend: 'pdf',
footer: true,
exportOptions: {
columns: ':visible'
}
},
it will export only visible columns

How to add multiple custom buttons in one row dynamically ? [JQuery Datatables]

I am using Datatables API but am not able to add multiple buttons in one row.
var table = $('#table_invdata').DataTable({
"columnDefs": [{
"targets": -1,
"data": null,
"defaultContent":
'<button class="btn-view" type="button">EDIT</button>'
}]
});
Try this code
var table = $('#table_invdata').DataTable({
"columnDefs": [{
"targets": -1,
"data": null,
"defaultContent":
'<button class="btn-view" type="button">EDIT</button>'
+ '<button class="btn-delete" type="button">Delete</button>'
}]
});
Or
var table = $('#table_invdata').DataTable({
"columnDefs": [{
"targets": -1,
"data": null,
"defaultContent":
'<button class="btn-view" type="button">EDIT</button> <button class="btn-delete" type="button">Delete</button>'
}]
});
Update :
You can use datatable render function to update the column values.
<table class="table" id="datatable" >
<thead>
<tr>
<th>Name </th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Jquery Datatable Code :
$('#datatable').DataTable ({
"data" : FinalResult,
"columns" : [
{ "data" : Name},
{ "data" : null,render: function ( data, type, row ) {
return '<button class="btn-view" type="button">EDIT</button>';
} },
{ "data" : null,render: function ( data, type, row ) {
return '<button class="btn-delete" type="button">Delete</button>';
} }
]
});
Fiddel Link : https://jsfiddle.net/jijomonkmgm/j6madey4/
<table id="table_invdata" class="table table-striped table-bordered">
<tr>
<th>EmpID</th>
<th>EmpName</th>
<th>Email-id</th>
<th>Salary</th>
<th>Position</th>
<th></th>
</tr>
</table>

Loop over response objects based on condition angular 5

I have a rest response which i want to loop over but based on condition, here's my response:
{
"veichleType": "SUV",
"veichleBrand": "BMW",
"veichleModels": [{
"veichleModel": "M3",
"property1": "value",
"property2": "value",
"property3": "value"
},
{
"veichleModel": "M1",
"property": "value",
"property2": "value",
"property3": "value"
}
]
}
I want in the UI to show only one object based on veichleModel if user searched by M3 then display that object response in the table, else show M1.
<table>
<thead>
headings here
</thead>
<tbody *ngIf='serviceResponse.veichleModels'>
<tr *ngFor="let veichleModel of serviceResponse.veichleModels">
<td>{{veichleModels.property1}}</td>
<td>{{veichleModels.property2}}</td>
<td>{{veichleModels.property3}}</td>
</tbody>
</table>
You need to do two things here :
Add some variable to store the selected model M1 or M3
Add condition inside loop to display respective object properties (Make use of ng-container)
Doing so, you can scale your array to 100 or more objects
template
<tbody *ngIf='serviceResponse.veichleModels'>
<tr *ngFor="let veichle of serviceResponse.veichleModels">
<ng-container *ngIf="veichle.veichleModel == selected">
<td>{{veichle.property1}}</td>
<td>{{veichle.property2}}</td>
<td>{{veichle.property3}}</td>
</ng-container>
</tr>
</tbody>
ts file
export class AppComponent {
selected = 'M1';
serviceResponse = {"veichleModels": [{
"veichleModel": "M3",
"property1": "M3val1",
"property2": "M3val2",
"property3": "M3val3"
},
{
"veichleModel": "M1",
"property1": "M1val1",
"property2": "M1val2",
"property3": "M1val3"
}
]}
}

Vue - how to bind table column to a data object?

I'm new to Vue, so go easy on me! Here's the situation. There must be a better way than what I'm doing here.
I have a simple 2 column HTML table:
<table id="contacts">
<tbody>
<tr>
<th class="column-1">
Contact Id
</th>
<th class="column-2">
Applications assigned count
</th>
</tr>
<tr class="odd" id="contacts_tr_1">
<td class="column-1">
1
</td>
<td class="column-2">
247
</tr>
<tr class="even last" id="contacts_tr_2">
<td class="column-1">
2
</td>
<td class="column-2">
0
</td>
</tr>
<tr class="even last" id="contacts_tr_2">
<td class="column-1">
3
</td>
<td class="column-2">
44
</td>
</tr>
<tr class="even last" id="contacts_tr_2">
<td class="column-1">
.........
</td>
<td class="column-2">
.........
</td>
</tr>
<tr class="even last" id="contacts_tr_2">
<td class="column-1">
10
</td>
<td class="column-2">
76
</td>
</tr>
</tbody>
</table>
I want to update the "Applications assigned count" column (but only for certain rows), as determined by the result of an AJAX call. So assuming the table has 10 rows, the AJAX call might say that the value of the "Applications assigned count" column of rows 1, 4 and 7 need to be updated, to e.g. 247, 80 and 356 respectively. I'm thinking of using a JSON object like this as my Vue data object, because the AJAX response will look like this.
data: {
num_of_applications_assigned: [
{
"party_id": "1",
"num": "247"},
{
"party_id": "4",
"num": "80"},
{
"party_id": "7",
"num": "356"}
]
},
I thought there might be a way to bind the "Applications assigned count" column to the Vue data object that gets updated by the AJAX call, but I don't see a way to do this other than adding a unique v-text to each individual <TD> cell e.g.
<div v-text="num_of_applications_assigned_1"></div>
<div v-text="num_of_applications_assigned_2"></div>
etc
However, this has lead me to writing some very convoluted code when updating those v-texts with the results of the AJAX response, as I have to dynamically construct the references:
let vm = this;
jQuery.ajax({
url: myurl
}).then(function(response) {
for (var i = 0, len = vm.num_of_applications_assigned.length; i < len; i++) {
var party_id = vm.num_of_applications_assigned[i].party_id;
var dref = 'vm.num_of_applications_assigned_'+party_id;
var dnum = vm.num_of_applications_assigned[i].num;
eval(dref + ' = ' + dnum + ';');
}
});
Yes, I know eval is bad - that's why I'm here asking for help! What is a better way of doing this, or is Vue not a good match for this situation?
I can't use v-for, as the table and its rows are all generated server side
If you cannot use v-for you can still use Vue to render your data, if you decide to do some additional work on the server-side, and you mould your data a little differently. It's less elegant than v-for but it should be straightforward.
For example, if you wanted to create a two-column table where Vue would render/update the second column's cell values, you could generate something like this on the server side:
<table id="app">
<tr>
<td>1</td>
<td>{{ applications.party_1.num }}</td>
</tr>
<tr>
<td>2</td>
<td>{{ applications.party_2.num }}</td>
</tr>
</table>
Where you use your favourite server-side language to generate values party_1, party_2, party_3 dynamically.
This implies that an underlying data structure like so:
applications: {
party_1: { num: 1 },
party_2: { num: 2 }
}
This should be straightforward to create that structure dynamically on the server-side. Then, just create a Vue instance and populate its initial data object with that data structure:
new Vue({
el: '#app',
data: {
applications: {
party_1: { num: 1 },
party_2: { num: 2 }
}
}
});
When the HTML is rendered in a browser, the Vue instance mounts and it will update the bound cell values from its data object. These values are reactive, so any subsequent changes to the Vue instance's underlying data will be rendered automatically.
Hope this helps :)
The idea in Vue is to have all your data ready, and let Vue.JS do the rendering. So, your data should probably look like this:
data: {
assignedApplications: [
{ party_id: 1, num: 247 },
{ party_id: 2, num: 0 },
{ party_id: 3, num: 44 },
{ party_id: 4, num: 76 },
{ party_id: 5, num: 9 },
]
},
}
Then, you can let Vue render it:
<table>
<tr>
<th class="column-1">Contact Id</th>
<th class="column-2">Applications assigned count</th>
</tr>
<tr v-for="a in assignedApplications">
<td>{{a.party_id}}</td>
<td>{{a.num}}</td>
</tr>
</table>
Remains the problem, how to update it. After getting the new data, you have to modify the array this.assignedApplications, and then Vue will re-render the table correctly. If your rows have a unique id, you could make assignedApplications instead of an array a map-like data structure, so you can easy access specific rows by their id and change the value. If not, you have to search through the whole array for every change and adapt it:
mergeInNewData(newData) {
for (let i = 0; i < newData.length; i++) {
let changedData = newData[i];
for (let j = 0; j < this.assignedApplications.length; j++) {
if (this.assignedApplications[j].party_id === changedData.party_id) {
this.assignedApplications[j].num = changedData.num;
}
}
}
}
All together, an example could look like this:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<table>
<tr>
<th class="column-1">Contact Id</th>
<th class="column-2">Applications assigned count</th>
</tr>
<tr v-for="a in assignedApplications">
<td>{{a.party_id}}</td>
<td>{{a.num}}</td>
</tr>
</table>
Update
</div>
<script>
var app = new Vue({
el: '#app',
data: {
assignedApplications: [
{ party_id: 1, num: 247 },
{ party_id: 2, num: 0 },
{ party_id: 3, num: 44 },
{ party_id: 4, num: 76 },
{ party_id: 5, num: 9 },
]
},
methods: {
update: function() {
let newData = [
{ party_id: 1, num: 243},
{ party_id: 2, num: 80},
{ party_id: 4, num: 0},
];
this.mergeInNewData(newData);
},
mergeInNewData(newData) {
for (let i = 0; i < newData.length; i++) {
let changedData = newData[i];
for (let j = 0; j < this.assignedApplications.length; j++) {
if (this.assignedApplications[j].party_id === changedData.party_id) {
this.assignedApplications[j].num = changedData.num;
}
}
}
}
}
})
</script>
</body>
</html>

Bootstrap table: add data-id to <tr> from remote source

I have a bootstrap table with data from remote source, but I can't find how to add data to .
This is my source data:
$ajax[] = array(
"qta" => $row['qta'],
"name" => $row['name'],
"description" => $row['description']
);
but I would like to have it like:
$ajax[] = array(
"id" => $row['id'], //123
"qta" => $row['qta'],
"name" => $row['name'],
"description" => $row['description']
);
in order to have my table row like:
<tr data-pk="123">
<td>...qta...</td>
<td>...name...</td>
<td>...description...</td>
</tr>
How could I achieve this? Maybe some responseHandler? I'm pretty new to BS Table.
Use Data-tables
HTML table
<table id="data" class="display table table-striped table-bordered">
<thead>
<tr>
<th>Row 1</th>
<th>Row 2</th>
<th>Row 3</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Server side
//List list = new LinkedList();
rs1 = s1.executeQuery("select * from somewhere");
obj = new JSONObject();
obj.put("row1", rs1.getString("rowfromdb1"));
obj.put("row2", rs1.getString("rowfromdb2"));
obj.put("row3", rs1.getString("rowfromdb3"));
//list.add(obj);
//return obj;
//return list
And JavaScript for Fill in data
//settings for your datatable
$(document).ready(function() {
$('#data').DataTable({
"columns": [{
"data": "row1",
"width": "30%"
}, {
"data": "row2",
"width": "30%"
}, {
"data": "row3",
"width": "40%"
}]
});
});
//ajax call which fill up your table on load of your page/change value of some object
$.ajax({
type: "GET",
url: "myScript",
data: "param1=" + value,
success: function(msg) {
$('#data').dataTable().fnClearTable();
$('#data').dataTable().fnAddData(
JSON.parse(msg.trim())
);
}
}
});
Hope it helps you