bootstrap-table: how to nest one table into another? - javascript

I'm using this bootstrap-table. I'd like to nest one table into another.
$(document).ready(function() {
var t = [{
"id": "1",
"name": "john",
}, {
"id": "2",
"name": "ted"
}];
//TABLE 1
$('#summaryTable').bootstrapTable({
data: t,
detailFormatter: detailFormatter
});
function detailFormatter(index, row, element) {
$(element).html(row.name);
$(element).html(function() {
//I was thinking of putting the code here, but I don't know how to do it so it will work,
//except javascript, it needs to be put this html code <table id="detailTable"></table>
});
// return [
// ].join('');
}
//TABLE 2
var t2 = [{
"id": "1",
"shopping": "bike",
}, {
"id": "2",
"shopping": "car"
}];
$('#detailTable').bootstrapTable({
data: t2,
columns: [{
field: 'id',
title: 'id'
}, {
field: 'shopping',
title: 'Shopping detail'
}, {
field: 'status',
checkbox: true
}],
checkboxHeader: false
});
$('#detailTable').on('check.bs.table', function(e, row, $el) {
alert('check index: ' + row.shopping);
});
$('#detailTable').on('uncheck.bs.table', function(e, row, $el) {
alert('uncheck index: ' + row.shopping);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.0/bootstrap-table.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.0/bootstrap-table.min.js"></script>
<div class="container">
<p>TABLE 1</p>
<table id="summaryTable" data-detail-view="true">
<thead>
<tr>
<th data-field="id" data-align="center" data-width="20px">id</th>
<th data-field="name" data-align="center">Name</th>
</tr>
</thead>
</table>
<br>
<p>TABLE 2</p>
<table id="detailTable"></table>
</div>
Here is the link of my demo: fiddle
There are two tables. Table 1 has expandable rows and I want to put Table 2 into every row of table 1. There is this function called detailFormatter which does this and where you can return a string or render an element (I was playing with it, but I can't make it work). For this demo the table 1 is created with some html code and the table 2 uses only javascript, but there is this initiating div <table id="detailTable"></table> (it doesn't matter for me which way is done). So, the question is how to put the table 2 into table 1 with possibility of using its events (like check or uncheck checkbox) as the demo shows for table2? Later on, I'd like to use this event onExpandRow so when the user expands the row of table 1 it will get the data from a database and it'll fill out the table 2.

Well just clone your detailTable and put it in each row with detailFormatter as below:
function detailFormatter(index, row, element) {
$(element).html($('#detailTable').clone(true));
}
Now there will be duplicate id's created when you do clone, so you just remove it by changing its id as below:
function detailFormatter(index, row, element) {
$(element).html($('#detailTable').clone(true).attr('id',"tbl_"+row.id));
}
Also, you can hide the #detailTable since you are just having it to append it in another table and once you hide it you need to add show to cloned tables as all the properties will be copied to in clone(true) which can be done as below:
function detailFormatter(index, row, element) {
$(element).html($('#detailTable').clone(true).attr('id',"tbl_"+row.id).show());
}
//.....
//.....
//.....
//At the end
$("#detailTable").hide();
A complete DEMO

I found another way of nesting one table into another using (partly) dynamic table creation (referring to my posted question when using bootstrap-table).
var expandedRow = row.id;
$(element).html(
"<table id='detailTable"+expandedRow+"'><thead><tr><th data-field='id2' data-align='center' data-width='20px'>id2</th>" +
"<th data-field='shopping' data-align='center'>Shopping detail</th>" +
"<th data-field='status' data-checkbox='true'></th>" +
"</tr></thead></table>");
$('#detailTable'+expandedRow).bootstrapTable({
data: t2,
checkboxHeader: false
});
I think this way is more independent. There is no need to have one panel opened at the time. The events and methods seems to be working fine.
Full code here.

Related

jQuery Datatables: Combining column visibility with individual column filters (text inputs)?

I am using basic column visibility and individual column searching (text inputs).
The problem is that when the user adds a previously-hidden column to the table, the text field box for that column does not appear. Thus, the user cannot filter that column.
Does anyone know how to enable filters for hidden columns as well? Ideally, this would not cause a byproduct of clearing the text in the other filters (if the user did enter text in the other filters).
Here is my filtering code:
<script type="text/javascript">
$(document).ready(function() {
// Setup - add a text input to each footer cell
$('#tableID tfoot th').each( function () {
var title = $(this).text();
if ((title != '') && !(title.includes("$"))) {
// Then the current column is *not* the Action column.
$(this).html( '<span style="color: #515151; font-size:15px;"><i>Filter</i></span> <br> <input type="text" style="margin-top:10px;" placeholder="'+title+'" /> ' );
}
} );
var table = $('#tableID').DataTable();
// Apply the search
table.columns().every( function () {
var that = this;
$( 'input', this.footer() ).on( 'keyup change', function () {
if ( that.search() !== this.value ) {
that
.search( this.value )
.draw();
}
});
} );
} );
</script>
I am using this line to hide the columns that I want to be hidden from view by default:
(table.column('.hideCol')).visible(false);
There's a custom column-visibility event in DataTables. So, you may revise your <input> elements visibility based on current status of the column.
E.g. you have <input> rendering function, like that:
//function to render input elements
const renderTfootInputs = () => {
//grab previous inputs into array
const prevInputs = [];
dataTable.columns().every(function(){
prevInputs.splice(this.index(), 1, $(`#example tfoot [colindex="${this.index()}"]`).val());
});
//purge <tfoot> row contents
$('#example tfoot tr').empty()
//iterate through table columns
dataTable.columns().every(function(){
//if the column is visible
this.visible() ?
//append corresponding footer <input>
$('#example tfoot tr').append(`<th><input colindex="${this.index()}" placeholder="${$(this.header()).text()}" value="${prevInputs[this.index()] || ''}"></input></th>`) :
true;
});
};
Than, you may call it upon column visibility changes:
$('#example').on('column-visibility.dt', renderTfootInputs);
Complete demo of this approach might look as follows:
//sample data source
const dataSrc = [
{id: 1, title: 'apple', cat: 'fruit'},
{id: 2, title: 'pear', cat: 'fruit'},
{id: 3, title: 'banana', cat: 'fruit'},
{id: 4, title: 'carrot', cat: 'vegie'},
{id: 5, title: 'eggplant', cat: 'vegie'}
];
//datatables initialization
const dataTable = $('#example').DataTable({
data: dataSrc,
dom: 'Bfrtip',
buttons: ['colvis'],
columns: ['id','title','cat'].map(header => ({title: header, data: header})),
columnDefs: [
{targets: 0, visible: false}
]
});
//append blank footer to the table
$('#example').append('<tfoot><tr></tr></tfoot>');
//function to render input elements
const renderTfootInputs = () => {
//grab previous inputs into array
const prevInputs = [];
dataTable.columns().every(function(){
prevInputs.splice(this.index(), 1, $(`#example tfoot [colindex="${this.index()}"]`).val());
});
//purge <tfoot> row contents
$('#example tfoot tr').empty()
//iterate through table columns
dataTable.columns().every(function(){
//if the column is visible
this.visible() ?
//append corresponding footer <input>
$('#example tfoot tr').append(`<th><input colindex="${this.index()}" placeholder="${$(this.header()).text()}" value="${prevInputs[this.index()] || ''}"></input></th>`) :
true;
});
};
//initial call of above function
renderTfootInputs();
//call that function each time upon column visibility changes
$('#example').on('column-visibility.dt', renderTfootInputs);
//individual search
$('#example').on('keyup', 'tfoot input', function(event){
dataTable.column($(event.target).attr('colindex')).search($(event.target).val()).draw();
});
tfoot input {
display: block;
}
tfoot th {
padding-left: 10px !important;
}
<!doctype html>
<html>
<head>
<script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/buttons/1.5.6/js/dataTables.buttons.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/buttons/1.5.6/js/buttons.colVis.min.js"></script>
<script type="application/javascript" src="test.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/1.5.6/css/buttons.dataTables.min.css">
</head>
<body>
<table id="example"></table>
</body>
</html>
I have worked with this small snippet to hide/Unhide the Individual Column Search, Integrated with Column Visibility Event of Datatables.
$('#table').on( 'column-visibility.dt', function ( e, settings, column, state ) {
columnv = settings.aoColumns[column].bVisible;
if(columnv === false){
$('#table').find("tr.filters th:eq('"+column+"')").hide();
}else{
$('#table').find("tr.filters th:eq('"+column+"')").show();
}
});

Typeahead and first cell selector

I have this table
<table id="vehicleParamTable" class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
When a click on a link, I add a row. That work fine.
In the first column of the row, I add an jquery-typehead
Selector is not working, also would like to avoid it for first row (th header)
$('#vehicleParamTable tr td:first-child').typeahead({
minLength: 2,
display: "name",
mustSelectItem: true,
emptyTemplate: function(query) {
//must reset current element here
return 'No result for "' + query + '"';
},
source: {
vehicleParam: {
ajax: {
url: "/rest/vehicleparam",
path: "content"
}
}
},
callback: {
onEnter: function(node, a, item, event) {
//must assign item.id to current current element id
},
onResult: function(node, query, result, resultCount, resultCountPerGroup) {
if (resultCount < 1) {
//must reset current element here
}
}
}
});
Edit
$('#vehicleParamTable tr td:first-child')
seem good, but with the rest(typeahead init..) that return undefined
Edit 2 because I add dynamicly row, need to refresh typehead...
I am assuming you are using this https://github.com/running-coder/jquery-typeahead?
This plugin needs to be initialized on an input field.
So, given that your input field is in the first column of the first row after the header, the selector would be
$('#vehicleParamTable tbody tr td:first-child input').typeahead({ ...options })

How to activate sorting in this table?

I am using DataTable plugin. The examples in the linked page are great. But I have a problem.
In the example user may sort the datatable after doing a search. I successfully do this. But when I created a filter, the sorting is messed up.
This is the expected sequence:
Page shows all data in the datatable
User do a filter (Show data by some filter. Like by date, by status, by country etc)
Page show certain data with the searched filter
User may do a search using text to view less data
User may do sort by column
In my script, the code works until point 3. When user do a search the filtered data is reset to show all data(not-filtered)
How do I deal with this?
This is my table:
<table id="tbl_surat_all" class="table table-striped table-bordered table-hover dataTables-example" >
<thead>
<tr>
<th class='text-center' width="1%">No</th>
<th class="text-center" width="10%">ID Proyek</th>
</tr>
<tbody><!--Data collected from php--></tbody>
</thead>
<tbody>
The jQuery:
$('.dataTables-example').DataTable({
pageLength : 25,
responsive : true,
dom : '<"html5buttons"B>lTfgitp',
buttons : [
{extend: 'copy'},
{extend: 'csv', title : "list<?php echo date('d/m/Y'); ?>"},
{extend: 'excel', title : "list<?php echo date('d/m/Y'); ?>"},
{extend: 'pdf', title : "list<?php echo date('d/m/Y'); ?>"},
{extend: 'print',
customize: function (win){
$(win.document.body).addClass('white-bg');
$(win.document.body).css('font-size', '10px');
$(win.document.body).find('table').addClass('compact').css('font-size', 'inherit');
}
}
]
});
This this the filter do (It's ajax success call):
var row;
var no = 1;
$('#tbl_surat_all tbody tr').remove();
$.each(response, function(index, data) {
row = "<tr><td>"+ no++ +"</td><td>"+data.idproyek+"</td></tr>";
$('#tbl_surat_all tbody').append(row);
});
Note:
the conclusion is how do I copy the search behavior (default from the library) to my filter (my own created jquery) behavior?
If you look at the search api, you can either search on the table as shown.
var table = $('#example').DataTable();
// #myInput is a <input type="text"> element
$('#myInput').on( 'keyup', function () {
table.search( this.value ).draw();
} );
Or you can name your columns when you initialize the datatable and search each column for text and apply that to the datatable.
columns: [
{
name: 'colName',
data: 'colData',
type: 'date'
}
searching on the column would be
var col = table.columns('colname:name');
col.search('searchTerm');
table.draw();

Dynamic column header in datatable from json array

I want to populate a Datatable with a dynamic column header and column data. I can populate dynamic column data successfully, but I can't achieve a dynamic column. I am using an array I get from a JSON AJAX request. My code is this:
<body>
<table id="example" class="display" cellspacing="0" width="100%" border="1"></table>
</body>
var JSONResult = '{"column1":"data1","column2":"data2","column3":"data3","columnN":"dataN"}';
var row_dtable = new Array();
var dtable_api = $('#example').dataTable();
$.each(JSONResult , function(key, value) {
row_dtable.push(value);
});
dtable_api.api().row.add(row_dtable).draw(false);
Thanks in advance.
Datatables doesn't have the ability to change it's structure once being created. You have to destroy it and then re-create with a new set of columns.
Additional reading: How to dynamically change Datatables multiple column headers using ajax and jquery without refreshing the webpage?
Ideally your JSONResult will always have the same columns and only data will be updated. For this the solution will be to create the columns once in the header of your table and then using the datatable API to add the data.
First you should change your table HTML like this, which shouldn't be a problem.
<body>
<table id="example" class="display" cellspacing="0" width="100%" border="1">
<thead>
<tr></tr>
</thead>
</table>
</body>
Then you create the headers through jQuery
var JSONResult = [{ "column1": "data1", "column2": "data2", "column3": "data3", "columnN": "dataN" },
{ "column1": "data1", "column2": "data2", "column3": "data3", "columnN": "dataN" }];
$.each(JSONResult[0], function (key, value) {
$('#example thead tr:first-child').append($('<th>', {
text: key
}));
});
And last, add the data to dataTable
var row_dtable = new Array();
var dtable_api = $('#example').dataTable();
$.each(JSONResult, function (i, l) {
$.each(l, function (key, value) {
console.log(key + " " + value);
row_dtable.push(value);
});
dtable_api.api().row.add(row_dtable).draw(false);
});

How do I render X <option>s in a <select>using jQuery.tmpl?

I'm inserting rows in a <table> that are bound to a JSON object. A cell in the table contains a <select> that needs to contain the number of objects, so 7 objects would produce 7 <option>s, 1-7.
Can this be done in the template definition?
Edit: I've added sample data and markup. From this data, I would want to add 3 <option>s (1-3) to the DisplayOrder <select> and have the appropriate <option> selected for each <select>.
Example: http://jsfiddle.net/4SxTS/
var data = [{
"Id": 1,
"DisplayOrder": 1,
"LabelText": "Unit On-Line Status:"},
{
"Id": 2,
"DisplayOrder": 2,
"LabelText": "AGC Pct:"},
{
"Id": 3,
"DisplayOrder": 3,
"LabelText": "Main Steam Heat Rate
}];
<table border="1" cellpadding="0" cellspacing="0">
<thead><tr><th>Display Order</th><th>Label Text</th></tr></thead>
<tbody></tbody>
</table>
<script id="attributeTemplate" type="text/x-jquery-tmpl">
<tr>
<td><select name="DisplayOrder"></select></td>
<td><input type="text" name="LabelText" value="${LabelText}" /></td>
</tr>
</script>
I'm not sure exactly what you mean without some sample data and markup, but I think the main part of your question deals with looping through numbers and rendering an option tag for each number. You could do this by creating an array containing "N" elements and then using {{each}}, but I think that using a custom template tag works well here:
Define a {{for}} tag that iterates through numbers 0 to n:
$.extend(jQuery.tmpl.tag, {
'for': {
open: "for(var $i = 0; $i < $1; $i++) {",
close: "}"
}
});
Use the new tag in a template:
<script type="text/html" id="row-tmpl">
{{each Rows}}
<tr>
<td>${Title}</td>
<td>${Description}</td>
<td>
<select>
{{for $data.TotalObjects}}
<option>${$i}</option>
{{/for}}
</select>
</td>
</tr>
{{/each}}
</script>
Called with:
var rows = {
TotalObjects: 5,
Rows: [{
Title: 'Test Row',
Description: 'Test Row Description'
},
{
Title: 'Another Row',
Description: 'Another Row Description'
}]
};
Best demonstrated in a working example: http://jsfiddle.net/xgE3Y/
Your situation might be even simpler, but my answer should enable you to at least use a simple for loop in a template and act on each iteration's value.
Maybe something like this:
$(function () {
var thisSelectObjects = 8;
var thatSelectObjects = 2;
$.fn.setOptions = function (options) {
var settings = {
'selectNum': 1
};
return this.each(function () {
if (options) {
$.extend(settings, options);
}
for (i = 0; i < settings.selectNum; i++) {
$(this).append('<option>' + i + '<option/>');
}
});
};
$('#thisSelect').setOptions({ 'selectNum': thisSelectObjects });
$('#thatSelect').setOptions({ 'selectNum': thatSelectObjects });
});
Html:
<body>
<select id='thisSelect'></select>
<select id='thatSelect'></select>
</body>

Categories