I'm fairly new to coding. I have a jQuery datatable, and when I select a row, the tds of that row fill out html textboxes above the table. I'm trying to make it so whatever is entered into those textboxes (and upon pressing the save button), is then saved into the row.
Currently I have it so it saves 1 field/td. If I press on column 0, fill out the Name textbox and press save, it saves. But it works on any column. It should only be editing the correct td. Plus I want to edit the entire row, not just one td. I'm not sure how to accomplish this. Thanks for any help!
JSFiddle
Javascript:
var table = $('#example').DataTable();
(function () {
var table = document.querySelector('#example');
var name = document.querySelector('#nameinput');
var format = document.querySelector('#formatinput');
var address = document.querySelector('#addressinput');
var report = document.querySelector('#reportinput');
var alarm = document.querySelector('#alarminput');
table.addEventListener('click', onTableClick);
function onTableClick (e) {
var tr = e.target.parentElement;
var data = [];
for (var td of tr.children) {
data.push(td.innerHTML);
}
name.value = data[0];
address.value = data[1];
format.value = data[2];
report.value = data[3];
alarm.value = data[4];
console.log(alarm.value);
}
$("#saverow").click(function() {
var table1 = $('#data-table').DataTable();
var data = [];
data[0] = name.value;
data[4] = alarm.value;
console.log(name.value);
console.log(alarm.value);
table1.draw(true);
});
})();`
I've updated my code with what I've tried so far. Currently, what I type in the textboxes, correctly is displayed in the console (upon hitting the saverow button), now I cant figure out how to save that into the table.
i think it is mor responsive to edit data right in the table.
HTML:
<table id="example" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Format</th>
<th>Report Time</th>
<th>Alarms</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>Tiger#gmail.com</td>
<td>email</td>
<td>1PM</td>
<td>Master</td>
<td class="td-button"></td>
</tr>
<tr>
<td>Bill Gates</td>
<td>111-111-1111</td>
<td>sms</td>
<td></td>
<td>Master</td>
<td class="td-button"></td>
</tr>
</tbody>
</table>
JS:
var table = $('#example').DataTable();
$("#example tbody tr").click(function(){
if (! $(this).find("button").length)
{
$(this).find("td").each(function(){
if (!$(this).hasClass("td-button"))
{
var text = $(this).text();
$(this).html ('<input type="text" value="' + text + '">')
} else
$(this).html ('<button class="button-save">Save</button>')
})
}
})
$(document).on("click", ".button-save",function(){
var tr = $(this).parent().parent();
tr.find("td").each(function(){
if (!$(this).hasClass("td-button"))
{
var text = $(this).find("input").val();
$(this).text(text)
} else
$(this).html('');
})
})
https://jsfiddle.net/91wvw619/
Related
I was trying to build my first search function for a phonelist. Unfortunately it looks like, my filter function loops only trough the last column of the table.
Did i miss something? Or do i have to use a different approach for this?
PS: Pardon for the possible duplicate. All examples that i've found has been for PHP.
Many thanks in advance!
const phonelist = document.querySelector('table');
const searchInput = document.querySelector('#search');
const searchResult = document.querySelector('#search-result');
const searchValue = document.querySelector('#search-value');
// EVENTS
function initEvents() {
searchInput.addEventListener('keyup', filter);
}
function filter(e) {
let text = e.target.value.toLowerCase();
console.log(text);
// SHOW SEARCH-RESULT DIV
if (text != '') {
searchValue.textContent = text;
searchResult.classList.remove('hidden');
} else {
searchResult.classList.add('hidden');
}
document.querySelectorAll('td').forEach((row) => {
let item = row.textContent.toLowerCase();
if (item.indexOf(text) != -1) {
row.parentElement.style.display = 'table-row';
console.log(row.parentElement);
} else {
row.parentElement.style.display = 'none';
}
})
}
// ASSIGN EVENTS
initEvents();
<input id="search" />
<div class="phonelist">
<div id="search-result" class="hidden">
<p>Search results for <b id="search-value"></b>:</p>
</div>
<table class="striped">
<thead>
<tr>
<th>Phone</th>
<th>Fax</th>
<th>Room</th>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>165</td>
<td>516</td>
<td>1.47</td>
<td>Johnathan Doe</td>
<td>Sales</td>
</tr>
<tr>
<td>443</td>
<td>516</td>
<td>1.47</td>
<td>Jane Dow</td>
<td>Development</td>
</tr>
</tbody>
</table>
</div>
it looks like you are querying the wrong element
document.querySelectorAll('td').forEach((row) => {
I think you want to be querying the row
document.querySelectorAll('tr').forEach((row) => {
otherwise you are of overriding your class changes with whatever is the result of the last column
(and obviously apply the class on the tr and not the parent of the tr)
Your code is actually going through all the elements but the changes from last column are overriding changes from previous columns.
Let's say you searched for dow, 2nd row 4th column is matched and shows the parent but after that your loop goes to 2nd row 5th column which doesn't match and hides the parent row.
I have updated your code, as shown below you should loop through the rows, check if any of its columns are matching and update the row only once based on the result.
const phonelist = document.querySelector('table');
const searchInput = document.querySelector('#search');
const searchResult = document.querySelector('#search-result');
const searchValue = document.querySelector('#search-value');
// EVENTS
function initEvents() {
searchInput.addEventListener('keyup', filter);
}
function filter(e) {
let text = e.target.value.toLowerCase();
console.log(text);
// SHOW SEARCH-RESULT DIV
if (text != '') {
searchValue.textContent = text;
searchResult.classList.remove('hidden');
} else {
searchResult.classList.add('hidden');
}
document.querySelectorAll('tr').forEach(row => {
let foundMatch = false;
row.querySelectorAll('td').forEach(col => {
let item = col.textContent.toLowerCase();
foundMatch = foundMatch || item.indexOf(text) > -1;
});
if (foundMatch) {
row.style.display = 'table-row';
} else {
row.style.display = 'none';
}
});
}
// ASSIGN EVENTS
initEvents();
<input id="search" />
<div class="phonelist">
<div id="search-result" class="hidden">
<p>Search results for <b id="search-value"></b>:</p>
</div>
<table class="striped">
<thead>
<tr>
<th>Phone</th>
<th>Fax</th>
<th>Room</th>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>165</td>
<td>516</td>
<td>1.47</td>
<td>Johnathan Doe</td>
<td>Sales</td>
</tr>
<tr>
<td>443</td>
<td>516</td>
<td>1.47</td>
<td>Jane Dow</td>
<td>Development</td>
</tr>
</tbody>
</table>
</div>
I create my personal project, and I called this system as ordering system I used laravel for this and the front end javascript and jquery.
I have question
Question:
I used the append function of jquery to transfer value to other side. so i append input type number which the value automatically equal to 1
The question if I increment the value of input type number how the price double if i increase the value of number?
Example of my output
My Front end Codes:
var tbody = $('#myTable').children('tbody');
//Then if no tbody just select your table
var table = tbody.length ? tbody : $('#myTable');
//my logic to increment quantity but not working.
$("#qty_change").bind('keyup mouseup', function () {
alert("changed");
});
//function for getting the data from search product by clicking to the table row
$("tr#productClicked").click(function () {
//to get the price in tr
var price = $(this).closest("tr").find(".menu_price").text();
//to get the menu in tr
var menu_name = $(this).closest("tr").find(".menu_name").text();
//row count
var rowCount = $('table#myTable tr:last').index() + 1;
//append input to quantity the value is 1
var input = '<input type="number" name="qty_number" class="form-control" value="1" id="qty_change" />';
//Item must be editable
var contenteditable = 'contenteditable=true';
table.append('<tr><td>'+rowCount+'</td><td class="total">'+input+'</td><td '+contenteditable+'>'+menu_name+'</td><td>'+price+'</td><td>'+price+'</td></tr>');
});
Html Table:
<table class="table table-hover" id="myTable">
<thead>
<tr style="font-size: 14px; ">
<th scope="col">#</th>
<th scope="col">Qty</th>
<th scope="col">Item</th>
<th scope="col" style="text-align: right">Cost</th>
<th scope="col" style="text-align: right">Total</th>
</tr>
</thead>
<tbody style="font-size:14px;">
<tr>
{{-- <td>1</td>
<td>x 2</td>
<td contenteditable='true'>Feast Chicken</td>
<td align="right">$10.00</td>
<td align="right">$20.00</td> --}}
</tr>
</tbody>
</table>
New update:
$('.amount > input[type="number"]').on('input', updateTotal);
function updateTotal(e){
var value = e.target.value;
// Don't do anything if value is not valid
// else you will see NaN in result.
if (!value || value < 0)
return;
var $parentRow = $(e.target).parent().parent();
var $siblingTotal = $parentRow.find('.total');
var $siblingCost = $parentRow.find('.cost');
var cost = $siblingCost.text();
// parseInt and parseFloat because
// `value` and `cost` are strings.
value = parseInt(value);
cost = parseFloat(cost);
$siblingTotal.text(value * cost);
}
$("tr#productClicked").click(function () {
swal({
title: "Are you sure?",
text: "Once you will add it will automatically send to the cart",
icon: "warning",
buttons: true,
dangerMode: true,
})
.then((willDelete) => {
if (willDelete) {
swal("Poof! Your imaginary file has been deleted!", {
icon: "success",
});
swal("Menu Added", "You clicked the button!", "success");
//to get the price in tr
var price = $(this).closest("tr").find(".menu_price").text();
//to get the menu in tr
var menu_name = $(this).closest("tr").find(".menu_name").text();
//row count
var rowCount = $('table#myTable tr:last').index() + 1;
//append input to quantity the value is 1
var input = '<input type="number" value="1">';
//Item must be editable
var contenteditable = 'contenteditable=true';
table.append('<tr><td>'+rowCount+'</td><td class="amount">'+input+'</td><td '+contenteditable+'>'+menu_name+'</td><td class="cost">'+price+'</td><td class="total">'+price+'</td></tr>');
} else {
swal("Cancelled");
}
});
});
Listen for "input" event using jQuery's .on.
(Please note that "input" event has nothing to do with jQuery, it's a native JavaScript thing.)
This is a sample code, because the code you provided is not complete. But you should be able to get the concept:
Usual code sample
$('.amount > input[type="number"]').on('input', updateTotal);
function updateTotal(e){
var amount = parseInt(e.target.value);
if (!amount || amount < 0)
return;
var $parentRow = $(e.target).parent().parent();
var cost = parseFloat($parentRow.find('.cost').text());
var total = (cost * amount).toFixed(2);
$parentRow.find('.total').text(total);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Input</th>
<th>Cost per item</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="amount"><input type="number" value="1"></td>
<td class="cost">27</td>
<td class="total">27</td>
</tr>
<tr>
<td class="amount"><input type="number" value="1"></td>
<td class="cost">14.50</td>
<td class="total">14.50</td>
</tr>
</tbody>
</table>
For the sake of understanding
// Get all inputs with type="number"
// that is a child of <td class="amount">.
var $amountInput = $('td.amount > input[type="number"]');
// Attach "input" event listener to the input fields
// so that we know when the value changes and handle the changes.
// In this case, the event handler is the function "updateTotal".
$amountInput.on('input', updateTotal);
function updateTotal(e){
// Get the `input` element that triggers this event.
var $thisInput = $(e.target);
// Get the value of $thisInput
var amount = $thisInput.val();
// The `value` is a string,
// so we need `parseInt` to make it a number.
// Use `parseInt` because quantity can't have decimals.
amount = parseInt(amount);
// Don't do anything if value is not valid
// else you will see NaN in result.
if (!amount || amount < 0)
return;
// Get the parent <tr> of this input field
var $parentRow = $thisInput.parent().parent();
// Find the <td class="total"> element
var $siblingTotal = $parentRow.find('.total');
// Find the <td class="cost"> element
var $siblingCost = $parentRow.find('.cost');
// Get the cost from <td class="cost"> element
var cost = $siblingCost.text();
// The "cost" is a string,
// so we need `parseFloat` to make it a number.
// Use `parseFloat` because cost can have decimals.
cost = parseFloat(cost);
// Calculate the total cost
var total = amount * cost;
// .toFixed(2) to force 2 decimal places
total = total.toFixed(2);
// Update the total cost into <td class="total"> element
$siblingTotal.text(total);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Input</th>
<th>Cost per item</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="amount"><input type="number" value="1"></td>
<td class="cost">27</td>
<td class="total">27</td>
</tr>
<tr>
<td class="amount"><input type="number" value="1"></td>
<td class="cost">14.50</td>
<td class="total">14.50</td>
</tr>
</tbody>
</table>
Note
If you still have difficulties understanding, you might want to read:
Why prefix "$" sign in only some variable names? (Generally called the Hungarian Notation)
What is td.amount > input[type="number"]?
What is jQuery's .on()?
What is e.target?
What is jQuery's .val()?
What is parseInt()?
What is parseFloat()?
What does !value mean?
Why do you return nothing?
What is jQuery's .parent()?
What is jQuery's .find()?
What is jQuery's .text()?
What is .toFixed()?
To create jquery datepicker, we use the following function
$( function() {
$( "#datepicker" ).datepicker();
} );
<input type="text" id="datepicker">
I am trying to achieve a in-line editing functionality with a new record function as below
function createRowForAdd(){
var tRow = "<tr>"
for(var i = 0; i < array.length; i++){
var jsonObj = array[i];
tRow +="<td><input type='text' id='"+jsonObj.id+"' /></td>"
}
tRow += "</tr>";
return tRow;
}
function Add(){
var tRow = createRowForAdd();
$("#tblId tbody").append(tRow);
}
<button id="btnAdd" onclick="javascript:Add()">New</button>
<table id="tblId" border="1">
<thead>
<tr>
<th>Name</th>
<th>Birth Date</th>
<th>Joining Date</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
One or more columns may contain a date field. For those column(s), I would like to show a date picker. As I understand, document.ready function gets triggered once the DOM is ready. Is it possible to initiate a date picker on row add?
.datepicker() function just needs that the element is in the DOM, so you can execute it after you add the row without problems, applying your desired selector for that input fields.
About the selector, considering that you're going to have multiple datapicker inputs, avoid using the same id (id's are designed to be unique in the DOM). You better use a class instead.
function Add() {
var tRow = createRowForAdd();
$("#tblId tbody").append(tRow);
// When creating the row, set class="datepicker" the inputs of the row that
// has to be converted to a datetime picker. Then you just have to do this...
$("input.datepicker").datepicker();
}
Or even better, apply it only to the inputs from the new added row (the last one)...
function Add() {
$("#tblId tbody").append(createRowForAdd()).find('tr:last input.datepicker').datepicker();
}
EDITED: I can't see the value of your array variable, but looking at your code it looks like all the inputs of the same column will have the same id. As I mention earlier, avoid that because id's are designed to be unique in the DOM. If you need an id, you can use the row number to change the input for every id. Here you have an example with that idea...
HTML:
<button id="btnAdd">New</button>
<table id="tblId" border="1">
<thead>
<tr>
<th>Name</th>
<th>Birth Date</th>
<th>Joining Date</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
JQUERY:
// I'm making up the content of this array. The question doesn't show it.
var array = [
{ 'id': 'name', 'class': '' },
{ 'id': 'birthdate', 'class': 'datepicker' },
{ 'id': 'joiningdate', 'class': 'datepicker' },
{ 'id': 'something', 'class': '' }
];
function createRowForAdd(rowPos) {
var tRow = [];
for (var i=0, l=array.length; i<l; i++)
tRow.push('<td><input type="text" id="'+array[i].id+rowPos+'" class="'+array[i].class+'" /></td>');
return '<tr>' + tRow.join('') + '</tr>';
}
$('button#btnAdd').click(function() {
var rowPos = $("table#tblId tbody tr").length;
$("table#tblId tbody").append(createRowForAdd(rowPos)).find('tr:last input.datepicker').datepicker();
});
And the fiddle... https://fiddle.jshell.net/rigobauer/tpxnvpy4/
I hope it helps
Hi I am currently working on datatables and I wrote a code when a table row has been click there is a specific function that will be called.
The problem is when I click the table row for the table header it also does the function (IT MUST NOT).
Here is a snippet of my code when I click the table row there will be a function called.
$('#response-contact-container').on('click', 'tr', function(){
var table = $('#response-contact-container').DataTable();
var data = table.row(this).data();
$('#edit-contact-settings').modal('hide');
$('.modal-backdrop').remove();
var community_contacts = ['c_id','firstname','lastname','prefix','office','sitename','number','rel'];
var employee_contacts = ['eid','firstname','lastname','nickname','birthday','email','numbers','grouptags'];
var counter = 1;
var container = document.getElementById("contact-settings-wrapper");
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
for(var i=1; i< data.length; i++) {
var label = document.createElement("label");
var input = document.createElement("input");
if (data[0].charAt(0)=="c") {
var t = document.createTextNode(community_contacts[i].capitalize());
label.appendChild(t);
container.appendChild(label);
input.type = "text";
input.name = community_contacts[i];
input.className = "form-control";
input.value = data[i];
container.appendChild(input);
container.appendChild(document.createElement("br"));
} else {
var t = document.createTextNode(employee_contacts[i].capitalize());
label.appendChild(t);
container.appendChild(label);
input.type = "text";
input.name = community_contacts[i];
input.className = "form-control";
input.value = data[i];
container.appendChild(input);
container.appendChild(document.createElement("br"));
}
console.log(data[i]);
counter++;
}
$('#edit-contact').modal('show');
});
I want the header be able to not perform the function under the onclick in jQuery, but I don't want it to disable because I want to use the datatables built in feature that sort the cells.
Thanks
I interpret your question to be the following: when I click on a table row, can I call a click handler if and only if that row has <td> elements, not <th> elements, i.e. only when it is a non-header row?
To accomplish this, use the jQuery .has() selector. Specifically, in your code, instead of
...on('click', 'tr', ...
use
...on('click', 'tr:has(td)', ...
In the example below, the selected element's currentTarget result shows that it is indeed the row, and not the cell, that is the click's current target. Moreover, it calls the handler function (or not) as follows:
when you click on a normal data row, i.e. a row with all <td> cells
not when you click on a normal header row, i.e. a row with all <th> cells
when you click on a mal-formed row that (inappropriately) contains both <th> and <td> rows
You should never form a table row in the last way. However, that example show how the selector is working. Specifically, even if you click on the <th> cell in that row, the click handler will still fire because you are clicking on a cell in a row that contains at least one <td> cell. That should never be what you want, but it illustrates what's going on in terms of what is actually being selected.
var counter = 0;
$('#myTable').on('click', 'tr:has(td)', function(e) {
console.log(e.currentTarget);
});
$('#myTable').on('click', 'tr', function(e) {
counter += 1;
console.log(counter + ' clicks');
});
table {
border-collapse: collapse;
}
td, th {
border: black solid 1px;
padding: 0.5em;
text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<th>normal header row - cell #1 - <th></th>
<th>normal header row - cell #2 - <th></th>
</tr>
<tr>
<th>malformed (mixed) row - cell #1 - <th></th>
<td>malformed (mixed) row - cell #2 - <td></td>
</tr>
<tr>
<td>normal data row - cell #1 - <td></td>
<td>normal data row - cell #2 - <td></td>
</tr>
</table>
I have a table within a form that I want to append new rows as the user enters input in the last row of the table.
$('table.form-table').on('input', function() {
var tableID = '#' + $(this).closest('table').attr('id');
if(jQuery(this).closest('tr').is(':last-child')) {
var currTR = $(this).closest('tr');
var currTRhtml = '<tr>' + currTR.html() + '</tr>';
var nextRow = jQuery(currTRhtml);
var checkBox = jQuery('<td class="border-right checks"><input type="checkbox" name="del_000" value="000"></td>');
jQuery(tableID).append(nextRow);
checkBox.appendTo(currTR);
}
});
And the html code if needed (simplified/trimmed):
<table class="form-table" id="XXX" border="1" cellspacing="0" cellpadding="3">
<thead>
<tr class="main"><th nowrap colspan="3" align="left"
class="border-left border-top border-right">
<h3>XXX</h3></th>
</tr>
<tr>
<th>header</th>
</tr>
</thead>
<tbody>
<tr>
<input type="hidden" name="isnew" value="">
<td >
<input type="text"
name="new_text"
value="">
</td>
</tr>
</tbody>
</table>
The problem is that this works only once and does not continue appending new rows. It's as if the last-child filtering does not get reset...
Any thoughts?
The problem is that you need to use the event's target, rather than "this". Right now "this" refers to the current table, but you need to refer to the current input box and then use closest() to find its parent tr (and :first-child to make sure it's the last one). So your code needs to look more like this:
$('table.form-table').on('input', function(e) {
var tableID = '#' + $(this).closest('table').attr('id');
if ($(e.target).closest('tr').is(':last-child')) {
var currTR = $(e.target).closest('tr');
var currTRhtml = '<tr>' + currTR.html() + '</tr>';
var nextRow = $(currTRhtml);
var checkBox = $('<td class="border-right checks"><input type="checkbox" name="del_000" value="000"></td>');
$(tableID).append(nextRow);
checkBox.appendTo(currTR);
}
});
Notice I'm passing the event as "e" and then referencing the current input box with $(e.target).
Here's a working JS fiddle.
I suspect the problem is that you need to delegate the input event as the appended rows do not exist on $(document).ready(). Try doing something like this to delegate the handler:
$(document).ready(function () {
$('table.form-table tbody').on('input', 'tr', function () {
var self = $(this),
tableID = '#' + self.closest('table').attr('id'),
currTR = self.closest('tr'),
currTRhtml = '<tr>' + currTR.html() + '</tr>',
nextRow = $(currTRhtml),
checkBox = $('<td class="border-right checks"><input type="checkbox" name="del_000" value="000"></td>');
if (currTR.is(':last-child')) {
$(tableID).append(nextRow);
checkBox.appendTo(currTR);
}
});
});
Fiddle: http://jsfiddle.net/KW7ET/