So far this is my set-up of DataTables used in my own app:
But the input fields are not that UI-friendly or pleasing to look at. And so I happen to stumble upon this feature of DataTable, which is Inline Editing, and now instead of those unpleasant-looking input fields, I want to have the fields similar to the Inline Editing functionality of Data Tables, with the exception that there are no values "to be edited", just empty fields with placeholder texts.
Is that even possible? I tried to trace the example and it seems to make use of some DataTable.Editor, but I can't seem to grasp how to implement an empty field one instead of a "editable field with default contents" (like the examples found in the documentations).
Any help? Also, if appreciated, I'd like to have the Total Load to automatically be computed whenever the No. of Units and Power Rating is filled up. It is simply the (No. of Units * Power Rating).
Here's my initial code setup:
The table.js contains the initialization of the DataTables,
whilst globs.js contains the ajax query with the corresponding creation of rows in the table.
I just pasted the codes that are relevant to my questions, and disregarded the others (jQuery actions of the buttons and etc)
table.js (Initialized jQuery codes)
$(function() {
var table = $('#costcenter_table').DataTable({
"columnDefs": [
{
"targets": 4,
"visible": false,
"searchable": false,
"sortable": false,
"width": "75px"
}
]
});
});
globs.js (contains functions with Ajax queries)
function show_cost_tables(costcenter){
$.ajax({
url: '/costcenter/' + costcenter,
type: 'GET',
dataType: 'json',
async: true,
success: function(res){
if(res.status === "success"){
$('#costcenter_table').DataTable().clear();
for(var i = 0; i < res.count; i++){
var entry = res.data[i];
var buttons = '<div style="text-align: center;"><button class="btn btn-xs btn-primary add-unit"><span class="fa fa-plus"></span></button> ' +
'<button class="btn btn-xs btn-warning remove-unit"><span class="fa fa-minus"></span></button> ' +
'<button class="btn btn-xs btn-danger delete-load"><span class="fa fa-close"></span></button></div>';
$('#costcenter_table').DataTable().row.add([entry.name, entry.unit_count, entry.power_rating, entry.total_load, buttons]).draw();
}
} else {
console.log(res.status + " login details.");
$('#warning-login').modal('toggle');
}
}
});
}
table.html (the input fields at the footer here should be gone and be replaced by that Inline Edit fields of DataTables)
<table id="costcenter_table" class="table table-bordered table-striped" cellspacing="0" width="100%">
<thead>
<tr>
<th>Load</th>
<th>No. of Units</th>
<th>Power Rating</th>
<th>Total Load</th>
<th></th>
</tr>
</thead>
<tbody id ="costcenter_data">
</tbody>
<tfoot id="add-new-load" style="display: none;">
<tr>
<form id="new-load" role="form">
<th><input id="name" name="name" type="text" placeholder="Load Name"><br><br><input id="brand" name="brand" type="text" placeholder="Brand"></th>
<th><input id="unit_count" name="unit_count" type="text" placeholder="No. of Units"><br><br><input id="location" name="location" type="text" placeholder="Location"></th>
<th><input id="power_rating" name="power_rating" type="text" placeholder="Power Rating"></th>
<th><input id="total_load" placeholder="Total Load" type="text" disabled></th>
<th><button id="add-load" class="btn btn-primary add-load" >Add New Load</button></th>
</form>
</tr>
</tfoot>
</table>
PS. Please try to ignore the last two input fields (Brand and Location), they are supposed to be dropdowns and browse buttons respectively.
Related
I am using PHP and JQuery to build a data table, I am using jQuery's .sort() method to sort the table. However, it is not working as excepted.
For the text fields, nothing is changed (except that the rows are rendered again).
For the numeric fields, the table sorts in a really weird manner.
Clearly the ID does not make sense like this? Here is my JavaScript code:
const rows = tbody.find('tr').sort((a, b) => {
let first, second;
if ($(e.target).attr('data-order') === 'asc') {
second = a;
first = b;
$(e.target).attr('data-order', 'desc');
}
else {
second = b;
first = a;
$(e.target).attr('data-order', 'asc');
}
const firstTd = $(first).children().eq($(e.target).attr('data-index') - 1).text();
const secondTd = $(second).children().eq($(e.target).attr('data-index') - 1).text();
// Take care of numbers
try {
return firstTd - secondTd;
}
catch (e) {
// Value is string
const value = firstTd.localeCompare(secondTd, "en");
return value;
}
}).appendTo(tbody);
Here is the source code for my table (I just added two rows):
<table class="table">
<thead>
<tr>
<th>
<button class="btn btn-light data-table-sort"
data-index="1" data-order="asc">
id <span class="fa fa-sort" aria-hidden="true"></span>
</button>
</th>
<button class="btn btn-light data-table-sort"
data-index="3" data-order="asc">
Text <span class="fa fa-sort" aria-hidden="true"></span>
</button>
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>72</td>
<td>af7c16d8f1</td>
<td>2021-11-26 06:16:55</td>
<td>
<form method="POST">
<input type="hidden" name="id" value="72">
<input type="submit" name="action" value="Details"
class="btn btn-info">
<input class="btn btn-primary" name="action"
type="submit" value="Edit">
<input data-id="72"
class="btn btn-danger data-table-delete"
name="action" value="Delete" type="submit">
</form>
</td>
</tr>
<tr>
<td>7</td>
<td>bedd6af3ed</td>
<!-- The same form as previous row -->
</td>
</tr>
</tbody>
</table>
I have made sure that tbody contains the correct value. I am also selecting the correct column. The table has to be dynamic and reusable so I can't hardcode everything.
Note: I have already tried appending rows to the table instead of the <tbody> element.
You probably need to detach elements since you reattach it again later:
tbody.find('tr').detach().sort...
This may need readjustments depending on how jQuery arrays are returned but detaching elements is the main idea and other things should be pretty trivial.
I'm populating a table from my database and it looks like this :
<form name = "Form" role="form" action ="php/teilnehmen.php" method="POST">
<fieldset>
<table width="100%" class="table table-striped table-bordered table-hover" id="dataTables-example">
<thead>
<tr>
<th>ID</th>
<th>Studienfach</th>
<th>Teilnehmer/in</th>
<th>Teilnehmen</th>
</tr>
</thead>
<tbody>
//<?php php code.....
$i =0;
$sizeofstudienfaecherseperate =
count($studienfaecherseperate);
for ($i; $i < $sizeofstudienfaecherseperate; $i++) {
?>
<tr class="odd gradeX">
<td ><?php echo($i+1);?></td>
<td class="studienfach"><?php echo($studienfaecherseperate[$i]);?>
<input type="hidden" name="PARAM_STUDIENFACH" id="PARAM_STUDIENFACH"
value="<?php echo($studienfaecherseperate[$i]);?>"> </input>
</td>
<td ><?php echo($teilnehmer[$i]);?></td>
<td width="10%">
<?php if ($teilnahmestatus[$i] =="0"){ ?>
<button type="submit" class="btn btn-success use-address"
name="teilnehmern"id="teilnehmen">Teilnehmen</button>
<?php }else{?>
<button type="submit" class="btn btn-danger use-address" name="teilnahme-beenden"
id="teilnahme-beenden">Teilnahme beenden</button>
<?php }?>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</fieldset> <!-- /.table-responsive -->
the table is shown great, and my problem is when i try to submit my second column value "PARAM_STUDIENFACH" of a specific row to my php webservice. It always gives me back the last value. I know that because I'm using the same id in every row so it will be overwritten. I tried using JavaScript to return the value of the clicked row from other questions in the forum but it didn't work for me. I'm using a bootstrap table if that helps.
EDIT 1 :
Thanks to #Taplar answer I managed to find a solution to my problem. I used this JavaScript to retrieve the data and ajax to send a post request. This is the code I used :
$(".use-address").click(function() {
var item = $(this).closest("tr") // Finds the closest row <tr>
.find(".studienfach") // Gets a descendent with class="nr"
.text(); // Retrieves the text within <td>
$.ajax({
type: "POST",
dataType: "json",
url: "php/teilnehmen.php",
data: {PARAM_STUDIENFACH:item},
success: function(data){
alert(item);
},
error: function(e){
console.log(e.message);
}
});
});
my problem now is in the alert the "item" shows correctly but in my database it is saved as the following example :
item = a (shows in alert a)
item = a \n (it's saved like that in the database with spaces afeter \n)
i tried to trim the item before sending it but i got the same result
to get the item sent by ajax i'm using this line of code in :
$studienfach = null;
if(isset($_POST['PARAM_STUDIENFACH']))
$studienfach = $mysqli->real_escape_string($_POST['PARAM_STUDIENFACH']);
EDIT 2:
i managed to solve my second problem by doing this :
$pos= strpos($studienfach, "\\");
$studienfachtemp = substr($studienfach, 0,$pos);
trim($studienfachtemp);
if there is more elegent or correct way to do it ! please post it ! thank you all.
<elem1>
<elem2 class="getMe"></elem2>
<elem3></elem3>
</elem1>
Quick contextual lookup reference. Say you have a click event bound on all 'elem3' on your page. When you click it you want to get the associated 'elem2', not all of them. With the class you can contextually look this element up by doing...
//'this' being the elem3 that was clicked
$(this).closest('elem1').find('.getMe');
From the element you clicked, it will find the shared 'elem1' parent of both 'elem2' and 'elem3' and then find only the '.getMe' that belongs to that parent.
More reading material: http://learn.jquery.com/using-jquery-core/working-with-selections/
I'm using DataTable.js version 1.10.7 in my application. My intention is to get an Array of row data that was added to the table after initiation. I have followed a modified version of steps as in this documentation - https://datatables.net/reference/api/rows().data()
<!-- this form is filled and form values are added the datatable on submission-->
<div class="col-md-4">
<form action="../api/MaterialInPurchaseOrders/Create" id="create-material-in-purchaseOrder" method="POST">
<div id="name-group" class="form-group">
<label for="name">Material Name</label>
<select name="MaterialId" class="form-control" id="MaterialList"></select>
<br />
<label for="email">Quantity</label>
<input type="number" class="form-control" name="Quantity" placeholder="eg :- 100">
<label for="email">Quantity</label>
<input type="number" class="form-control" name="Cost" placeholder="eg :- 100">
</div>
<button type="submit" class="btn btn-default">Add Material to P/O<span class="fa fa-arrow-right"></span></button>
</form>
</div>
<!-- this table stores the rows that is being added from the form-->
<div class="col-md-8">
<table id="materials-in-purchase-order" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Material Id</th>
<th>Material Name</th>
<th>Quantity</th>
<th>Unit Cost</th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<th>Material Id</th>
<th>Material Name</th>
<th>Quantity</th>
<th>Unit Cost</th>
</tr>
</tfoot>
</table>
</div>
<button class="btn btn-success" id="get-table-data">Get Table Row Data</button>
<script>
// the Datatable handler
var materialsInPurchaseOrder = $("#materials-in-purchase-order").DataTable({
"dataSrc": "data",
"columns": [
{ "data": "MaterialId" },
{ "data": "MaterialName" },
{ "data": "Quantity" },
{ "data": "Cost" }
]
});
$(document).ready(function () {
// loading list boxes from database to an input selection list box in the form
loadListBox("../api/Materials/GetMaterials", "#MaterialList", "MaterialId", "MaterialName");
// on submission of the form the form values gets updated to the Datatable as a row.
$("#create-material-in-purchaseOrder").on("submit", function (event) {
var data = {};
data = getFormValues("#create-material-in-purchaseOrder");
$("#MaterialList option:selected").each(function () {
data["MaterialName"] = $(this).html();
});;
materialsInPurchaseOrder.row.add(data).draw(false);
event.preventDefault();
});
$("#get-table-data").click(function (event) {
var materials = materialsInPurchaseOrder.rows().data();
console.log(materials);
// looping through each row of the array and doing something
for (var material in materials) {
// unable to do this because materials is not an array :(
}
event.preventDefault();
});
});
</script>
I get the below output for the console.log() instead of an Array
[Object, context: Array[1], selector: Object, ajax: Object]
Some research I did,
jQuery DataTables - Access all rows data
How can I get an Array of DataTable row data.?
As per the documentation return type of rows().data() is DataTables.Api. Before print it with console.log first convert it to string using JSON.stringify(). Because DataTables.Api is an object.
Ex:
console.log('Materials',JSON.stringify(materials));
As per the documentation of DataTables.Api type The API object is array-like
You can access data by row index as follows,
materials[0]
This returns data of first row.
The problem is solved with the help of the answer by #Dushan. This answer demonstrates how the actual code is changed.
I replaced this code
for (var material in materials) {
// unable to do this because materials is not an array :(
}
with this code
// looping through each row until the last row
for (var i=0 ; i < materials.length ; i++) {
console.log(materials[i]);
}
The only thing I'm adding to #Dushan's answer is the for loop which loops through Objects of the data objects in DataTables.Api to demonstrate the use of DataTables.Api Object.
Summarizing what #Dushan pointed out in the documentation, the return type of the rows().data() method is a DataTables.Api object not an Array. This is an array like object which is of length equal to the number of rows in the DataTable instance.
JSFiddle: https://jsfiddle.net/dxhen3ve/4/
Hey guys,
I've been trying to figure out the issue here for some time.
Essentially, I have a table with rows. You can add new rows (works fine). However, on the deletion of rows, I would like to re-number all of the rows below it (including all of their input names/ids within).
This works fine as I have it on the first time you click "remove" for any row.. say, if you have rows 0-4 and delete row 1, you will now have rows 0-3 and they will be numbered correctly--however, after that if you click remove again on another row, the numbers do not update
The indexes are getting mixed up some how and it almost seems like it's not recognizing that I've removed an element from the DOM.. when I console.log the indexes everything looks fine.
As an example:
- Add 5 rows (0-4)
- Remove row #1 (the rows below get updated as they should).
- Remove the new row #1, and you will see that row #2 takes its place instead of changing to row #1.
- In the function 'renumber_budget_rows', the if statement seems to get skipped for that row #2, even though I feel like it should meet the conditions (and is present if I console.log(item)
What am I missing? https://jsfiddle.net/dxhen3ve/4/
** Update: Just wanted to update that I have a true resolution that works, which is great! However, I am more interested in knowing WHY my solution is failing. At the moment, the best I have, from the correct answer, was that my indexes were misaligned. I'm going to take a new look at them.
HTML
<script type="text/template" id="budget_row-template">
<tr id="budget_row-{{index}}" class="budget-row" data-budget-index="{{index}}">
<td class="budget-line">{{index}}</td>
<td><input type="text" name="budget_description-{{index}}" id="budget_description-{{index}}" class="budget-description" /></td>
<td><input type="text" name="budget_amount-{{index}}" id="budget_amount-{{index}}" class="budget-amount" /></td>
<td>
<select name="budget_costcode-{{index}}" id="budget_costcode-{{index}}" class="budget-costcode">
<option>-- Select Cost Code</option>
</select>
</td>
<td><i class="fa fa-share"></i></td>
<td>remove</td>
</tr>
</script>
<div class="table-scroll-container">
<table class="table table-striped table-bordered table-hover tablesorter" id="budget-display">
<thead>
<tr>
<th>Line #</th>
<th>Description</th>
<th>Amount</th>
<th>Cost Code</th>
<th data-sorter="false"></th>
<th data-sorter="false"></th>
</tr>
</thead>
<tbody id="test">
<tr id="budget_row-0" class="budget-row" data-budget-index="0">
<td class="budget-line">0</td>
<td><input type="text" name="budget_description-0" id="budget_description-0" class="budget-description" /></td>
<td><input type="text" name="budget_amount-0" id="budget_amount-0" class="budget-amount" /></td>
<td>
<select name="budget_costcode-0" id="budget_costcode-0" class="budget-costcode">
<option>-- Select Cost Code</option>
</select>
</td>
<td><i class="fa fa-share"></i></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="text-align-center">
<i class="icon icon-plus icon-white"></i> Add Line Item<br />
</div>
JS
function renumber_budget_rows(removed) {
$('#budget-display tbody .budget-row').each(function(indite, item) {
var ti = $(item).data('budget-index');
if( ti > removed ) {
ti--;
//console.log(item);
$(item).attr('id', 'budget_row-'+ti);
$(item).attr('data-budget-index', ti);
$(item).find('.budget-line').html(ti);
$(item).find('.budget-description').attr({ 'name': 'budget-description-'+ti, 'id': 'budget-description-'+ti });
$(item).find('.budget-amount').attr({ 'name': 'budget-amount-'+ti, 'id': 'budget-amount-'+ti });
$(item).find('.budget-costcode').attr({ 'name': 'budget-costcode-'+ti, 'id': 'budget-costcode-'+ti });
$(item).find('.add-budget-child').attr({ 'id': 'budget_row-addparent-'+ti, 'data-budget-index': ti });
$(item).find('.trash-budget-row').attr({ 'id': 'budget_row-'+ti+'-trash' });
$(item).find('.trash-budget-row').attr('data-budget-index', ti);
}
});
}
var budget_index = 0;
$('.add-budget-row').click(function(e) {
budget_index++;
e.preventDefault();
var budget_html = $('#budget_row-template').html();
budget_html = budget_html.replace(/{{index}}/g, budget_index);
$('#budget-display tbody').append(budget_html);
});
$('#budget-display').on('click', '.trash-budget-row', function(e) {
var removed = $(this).data('budget-index');
$(this).closest('tr').remove();
console.log(removed);
renumber_budget_rows(removed);
budget_index--;
});
While you are deleting the row, after a row deletion, you can iterate through every tr using .each() function and change the attributes based on the index i value.
$('#budget-display').on('click', '.trash-budget-row', function(e) {
var removed = $(this).data('budget-index');
$(this).closest('tr').remove();
$('tbody tr').each(function(i){
$(this).find('td').eq(0).text(i);
$(this).attr("data-budget-index",i);
$(this).attr("id","budget-row-" + i);
});
budget_index--;
});
Working example : https://jsfiddle.net/DinoMyte/dxhen3ve/5/
Starting off there is a append button that generates a row with 1 select box, 1 inputbox, and 4 checkboxes. The limit of adding this would be 1-10 rows at max. I have no idea how to make a jquery validation using for example http://formvalidation.io/ - or a standalone jquery code. The rules I would like to apply:
If the role chosen is user (not an admin) , I must validate that there is at least one checkbox checked and the user doesn't appears twice in the selections
The thing is I don't even know where to start from, can you point me any hints?
Live example :: http://jsfiddle.net/Yy2gB/131/
Append method onClick
$(document).ready(function(){
var obj = {"1":"Admin istrator","2":"User2"};
//$('.selectpicker').selectpicker();
$(".addCF").click(function(){
count = $('#customFields tr').length + 1;
var sel = $('<select name="user'+count+'">');
for(key in obj){
// The key is key
// The value is obj[key]
sel.append($("<option>").attr('value',key).text(obj[key]));
}
$('.selectpicker').selectpicker();
$("#customFields").append('<tr><td>'+sel[0].outerHTML
+'</td><td><input class="form-control" class="valid_role"'
+' data-fv-field="emails" type="text" name="role'+count
+'" /></td><td><input type="checkbox" class="mycheckbox"'
+' name="can_edit'+count+'"></td><td><input type="checkbox" '
+'class="mycheckbox" name="can_read'+count+'"></td><td><input '
+'type="checkbox" class="mycheckbox" name="can_execute'+count+'">'
+'</td><td><input type="checkbox" class="mycheckbox" '
+'name="is_admin'+count+'"></td><td><a href="javascript:void(0);"'
+'class="remCF">Remove</a></td></tr>');
$('.mycheckbox').iCheck({
checkboxClass: 'icheckbox_square-blue',
radioClass: 'iradio_square-blue'
});
$('.selectpicker').selectpicker();
});
$("#customFields").on('click','.remCF',function(){
$(this).parent().parent().remove();
});
});
HTML Form
<div class="col-md-12 col-lg-12">
<table class="table table-user-information" id="customFields">
<thead>
<tr>
<th class="standardTable_Header">User</th>
<th class="standardTable_Header">Role</th>
<th class="standardTable_Header">
<span title="administrator projektu">Can read</span>
</th>
<th class="standardTable_Header">
<span title="uprawnienie do edycji danych projektu">
edit
</span>
</th>
<th class="standardTable_Header">
<span title="uprawnienie do odczytu danych projektu oraz przypisanych do niego zadaĆ">
excute
</span>
</th>
<th class="standardTable_Header">
<span title="uprawnienie do edycji danych projektu">
admin
</span>
</th>
</tr>
</thead>
<tbody>
<button type="button" class="btn btn-default addCF">
Append
</button>
</div>
</tbody>
</table>
Using this jQuery Validation Plugin and through this demo, We could do the following:
Assumption: Roles check boxes must have at least one checked if - and only if - the select tag have the value User2
1- wrap your table with form tag that has a submit button:
<div class="col-md-12 col-lg-12">
<form id="myform">
<table class="table table-user-information" id="customFields">
...
</table>
<input type="submit" value="submit" />
</form>
</div>
2- We need to edit the checkboxes html to make them all have the same name but with different values, for example:
<input type="checkbox" class="mycheckbox" name="ourRoles" value="can_edit' ...>
<input type="checkbox" class="mycheckbox" name="ourRoles" value="can_read' ...>
and so on.
3- Add the following script:
// just for the demos, avoids form submit
jQuery.validator.setDefaults({
debug: true,
success: "valid"
});
$("#myform").validate({
rules: {
ourRoles: {
required: function () {
if ($("select[name=user2]").val() == 2) {
return true;
} else {
return false;
}
}
}
}
});
See all together with this fiddle