I have a table, that is dynamicallly increased with Firebase, and I need a delete and edit button on each row of the table, currently, the remove button is working, but I am having trouble with the edit button, I saw a few examples around, but i'm not sure how to do it using append()...
Here's what I have so far:
HTML
<table id="tableAssets" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">
<thead>
<tr id="tableHeader">
<th class="mdl-data-table__cell--non-numeric">Name</th>
<th class="mdl-data-table__cell--non-numeric">Brand</th>
<th class="mdl-data-table__cell--non-numeric"> </th>
</tr>
</thead>
<tbody id="table_body"> </tbody>
</table>
JavaScript
rootRef.on("child_added", snap => {
var assetKey = snap.child("id").val();
var name = snap.child("name").val();
var brand = snap.child("brand").val();
$("#table_body").append("<tr data-id='"+assetKey+"'>"+
"<td class='mdl-data-table__cell--non-numeric'>" + name + "</td>" +
"<td class='mdl-data-table__cell--non-numeric'>" + brand + "</td>" +
"<td class='mdl-data-table__cell--non-numeric'><div buttons>"+
"<button class='edit-btn'><i class='material-icons'>mode_edit</i></button>"+" "+
"<button class='delete-btn'><i class='material-icons'>delete</i></button>"+" "+
"</div></td></tr>");
});
And here is what I was thinking on doing with the edit button: Hide the whole row, and add a new one with the saved information, but with text fields, and change the edit button with a save button, but I have no idea how I should be doing this...
$("#table_body").on('click','.edit-btn', function(e){
var $row = $(this).closest('tr');
$row.hide();
});
I'd suggest you to do this:
Have two rows, one for view and one for edit mode. This is easier to
maintain.
Assign an id to the whole row:
$("#table_body").append("<tr id='"+assetKey+"'>
Then when clicking that edit button, pass the id to some method as when you append you have it, it is easier. You can use something
like onclick and call the method:
<button class='edit-btn' onclick=edit(\'"+assetKey+"\')><i class='material-icons'>mode_edit</i></button>
On edit, hide the clicked button row and show the edit mode for that row. As it is already rendered, it works great if you have
multiple rows, stays in place:
('#'+id).hide();
The edit mode row "view" would show the save button or anything else you need. Use the same Technique/strategy to call a save() method.
When save is successful, rebuild both rows and replace them so everything is neat and stays in line.
And to make sense of this and it is not just in words, a functional example using your code on jsfiddle here.
Hope this is of help!
Related
I have two tables at the moment. What Im looking to achieve is to select a row in one table, obtain the "filename" field from that and then check if that filename exists in the other table. If the file exists in both tables I want to change the colour of my progress tracker. Right now I have the selecting of the row working, but I can't seem to check it against the other table. Any help would be greatly appreciated.
HTML:
<table id="table">
<tr>
<td>--</td>
<td>Filename</td>
</tr>
<tr>
<td>1</td>
<td>Example1</td>
</tr>
<tr>
<td>2</td>
<td>Example2</td>
</tr>
</table>
<table id="table2">
<tr>
<td>--</td>
<td>Filename</td>
</tr>
<tr>
<td>1</td>
<td>Example1</td>
</tr>
</table>
<div id="words">
</div>
JavaScript:
$("#table").find("tr").click(function(){
$(this).addClass('selected').siblings().removeClass('selected');
var value=$(this).find('td:nth-child(2)').html();
//alert(value);
document.getElementById("words").innerHTML = value;
});
Thanks again for the help!
$("#table").on('click','tr',function(){ // <-- #1
var $this = $(this), // <-- #2
filename = $this.find('td:nth-child(2)').text(), // <-- #3
$words = $('#words');
$this.addClass('selected').siblings().removeClass('selected');
$words.html(filename).css('color','black');
if ( valueInTable('table2', 1, filename ) ){ // <-- #4
$words.css('color', 'blue');
}
});
function valueInTable(tableID, columnNum, searchString){
var found = false;
$( '#' + tableID + ' tr td:nth-child(' + columnNum + ')' ).each(function(){
if ($(this).text() == searchString ){
found = true;
return false;
}
});
return found;
}
This is important, this binds the event to the table. When a click occurs somewhere inside the table it checks the event registry, in this case, it checks to see if a TR was clicked. This is both a performance gain, since you're not creating an event for each row of the table, but also if you create new rows dynamically, you don't have to create a new event when you do. You create this event once and it's in place for all new/old rows of the table
Cache $(this) into a variable. You use it more than once and chances are you'll use it even more. You should not create a new jQuery object every time you want to refer to $(this), so stick it in a variable and reuse that
While .html() may work for you, if you have other embedded HTML, you might get values you were not intending (e.g., <span>filename</span>), for that reason, you only need .text(), which will just give you the text value and strip off all the nested HTML (leaving you with only filename)
Using a function comes with a penalty, but it's good to put long-logic elsewhere, in case you're doing anything more involved. For instance, your table could expand in width (number of columns) and you might also want to search them for a value, or you might have more tables you want to look in; this same function can be used for both of those cases.
as noted, the :contains() selector was built for what you're after However, there is one caveat. The problem with contains is that it lacks customization. If you want to modify your comparison to be a RegEx, or if you want to perform other manipulation using trim or truncate, you can't do that with contains. You could easily modify the code below to do: $.trim( $(this).text() ) == $.trim( searchString )
As #Pete commented, you can use if ($('#table2 td:contains(' + value + ')').length) as follows
$("#table").find("tr").click(function(){
$(this).addClass('selected').siblings().removeClass('selected');
var value=$(this).find('td:nth-child(2)').html();
//alert(value);
if ($('#table2 td:contains(' + value + ')').length) {
document.getElementById("words").innerHTML = value;
} else {
document.getElementById("words").innerHTML = "false";
}
});
See the JSFiddle for working example: https://jsfiddle.net/v14L4bqr/
I'm trying to print to page the rowIndex for each row in a table. I would like it to be placed inside the table itself, but I can't seem to get it to work:
<table>
<tr>
<td>r1.cell1</td>
<td>r1.cell2</td>
<td><script>document.write("rowindex = " + this.parentNode.rowIndex);</script></td>
</tr>
<tr>
<td>r2.cell1</td>
<td>r2.cell2</td>
<td><script>document.write("rowindex = " + this.parentNode.rowIndex);</script></td>
</tr>
</table>
Using jQuery is a simple matter of doing it after the document is loaded. Assuming this is the only table in the whole page you could do something like
$('td:last-child').each(function(index, item) { $(item).html(index)})
You can see it in action using this JSFiddle http://jsfiddle.net/qurm4304/
The goal: ,,
So I've got a Table (Which is initialized as a JQuery DataTable). Each row contains a 'remove me' button, and when that button is pressed, I want to delete the row from the current table.
What I've tried:
tr = $(this).closest('tr');
$('.my-table-class').dataTable().fnDeleteRow(tr);
What happens
No matter what row I click on, the last row is deleted from the table is deleted, except if there's only one row in the table, in this situation a javascript error: "TypeError: j is undefined" is thrown from Jquery.dataTable.min.js. Both baffle me.
I can get the attributes of the right row - for example, If do something like: alert($(this).attr("data-name")); I click on John Smith's row, I'll see 'John Smith' in an alert box... so $(this) is the a tag, so why doesn't the .closest() method grab the right trtag?
My Questions:
How do I get 'this' row (the one which contained the button which was pressed) in order to delete it?
Any idea what's causing the 'TypeError: j is undefined" error when there's only one row in the table?
Details:
Here's the rendered (from .jsp) HTML table:
<table class="table my-table-class">
<thead><tr><th>Name</th><th> </th></tr></thead>
<tbody>
<tr>
<td>John Smith</td>
<td><i class="icon-plus"></i></td>
</tr>
<tr>
<td>Robert Paulson</td>
<td><i class="icon-plus"></i></td>
</tr>
<tr>
<td>Juan Sanchez</td>
<td><i class="icon-plus"></i></td>
</tr>
</tbody>
Here's how I initialize the tables as a Jquery DataTable:
$('.st-my-table-class').dataTable( {
"bInfo": true,
"aaSorting": [[ 0, "desc" ]], // sort 1st column
"bFilter": true, // allow search bar
"bPaginate": false, // no pagination
"sDom": '<"top"f>rt<"bottom"lp><"clear">' // (f)ilter bar on top, page (i)nfo omitted
} );
And here's the whole event handler:
$('.my-button-class').on("click", function(){
tr = $(this).closest('tr');
$('.my-table-class').dataTable().fnDeleteRow(tr);
});
I think This JSFIDDLE is much closer to what you wanted. Here is the basic code
$(function() {
var dataTable = $('.my-table-class').dataTable();
$( ".test" ).click(function() {
var row = $(this).closest('tr');
var nRow = row[0];
dataTable.dataTable().fnDeleteRow(nRow);
});
});
which I pulled from this resource here that explains in full detail on how it works. In short you need to select the node itself not the jQuery object. You can also use .firstlike so.
$( ".test" ).click(function() {
var row = $(this).closest('tr').first();
dataTable.dataTable().fnDeleteRow(row);
Note: I added the "This" text as I don't have the button style/icon.
As #Dawn suggested, you're passing a jQuery element to fnDeleteRow, which is expecting a HTML node.
Simply try:
$('.my-button-class').on("click", function () {
tr = $(this).closest('tr').get(0); // gets the HTML node
$('.my-table-class').dataTable().fnDeleteRow(tr);
});
Working JSFiddle: http://jsfiddle.net/so4s67b0/
First of all in the function it is need to declare a variable and assign our data table to it. Then take the selected row's index into another variable. After that remove the selected row from the data table. .draw(false) will be manage the pagination and no of rows properties in jquery DataTable.
$('.my-button-class').click(function () {
var tbl = $('.my-table-class').DataTable();
var index = tbl.row(this).index();
var row = $(this).closest("tr").get(index);
tbl.row(index).remove().draw(false);
});
I am populating a html table based on data stored in parse.com. So the table is dynamically populated, I am including editing options for the user to add, delete and edit a row. I have managed to incorporate delete and add to the table however, my problem is I need to get the data in the cells of the row on which I click the edit button...
So what I want to do is when the user clicks on the edit button I'll open a dialog with the table row in it populated with the data in the row they have clicked, in this dialog they can change data and save. I've attached a screenshot of a sample table. So if the user clicks on the edit button on the second row, I need to obtain the data in each cell to populate the dialog.
Here is what I have tried:
var par = $(this).parent().parent(); //table row
var tdUuid = par.children("td:nth-child(1)");
var tdProx = par.children("td:nth-child(2)");
var tdOffer = par.children("td:nth-child(3)");
alert(tdUuid.html()); //for testing
This comes up as undefined.
I've also tried:
var value = $(this).children().get(1).text();
I've tried to display this in an alert but the alert doesn't display so I'm assuming this is way wrong...
If anyone could help me I'd greatly appreciate it. I'm VERY new to html/javascript and I'm feeling my way around in the dark!
EDIT
Here is my html as requested:
<div id="EditDialog" title="Edit iBeacon">
<p class ="editInfo">
Please edit fields and click save
</p>
<table id ="editingTable" class ="beaconTable ">
<thead>
<tr>
<th>UUID</th>
<th>Proximity</th>
<th>Offer</th>
</tr>
</thead>
<tbody></tbody>
</table>
<button id ="saveButton" class ="btnSave">Save</button> <button id ="cancelButton" class ="btnCan">Cancel</button>
</div>
<div id= "tableContainerHolder">
<div id = "tableContainer">
<button id ="buttonAdd">Add iBeacon</button>
<table id ="iBeaconTable" class ="beaconTable " >
<thead>
<tr>
<th>UUID</th>
<th>Proximity</th>
<th>Offer</th>
<th>Editing Options</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<script>
$(function() {
$("#EditDialog").dialog({
autoOpen: false
});
});
</script>
FURTHER EDIT
Here is how I populate my table:
$('#iBeaconTable').append('<tr><td id = "uuid">' + object.get('uuid') + '</td><td = "proxId">' + object.get('proximity') + '</td><td = "offerId">' + object.get('offer_content') + '</td><td><Button id = "btnEdit" onclick = "openDialog()">Edit</Button><Button id = "btnDelete" onclick = "Delete()">Delete</Button></td></tr>');
So I add the buttons each time in each row.
additional edit
Apologies for omitting code
function openDialog() {
var par = $(this).parent().parent(); //table row
var tdUuid = par.children("td:nth-child(1)");
var tdProx = par.children("td:nth-child(2)");
var tdOffer = par.children("td:nth-child(3)");
$("#EditDialog").dialog("open");
$('#editingTable').append('<tr><td id = "uuid">' +tdUuid.innerHTML+ '</td><td = "proxId">' + tdProx.html()+ '</td><td = "offerId">' + tdOffer.html());
}
The code in the openDialog() is what I had originally posted.
values in table are selected only after adding data dynamically. To get td values
var tr = $(this).closest('tr')
var tdUuid = $(tr).find('td').eq(0).text();
var tdProx = $(tr).find('td').eq(1).text();
var tdOffer = $(tr).find('td').eq(2).text();
Hope this should work.
I've been struggling with this issue for a while now. Maybe you can help.
I have a table with a checkbox at the beginning of each row. I defined a function which reloads the table at regular intervals. It uses jQuery's load() function on a JSP which generates the new table.
The problem is that I need to preserve the checkbox values until the user makes up his mind on which items to select. Currently, their values are lost between updates.
The current code I use that tries to fix it is:
refreshId = setInterval(function()
{
var allTicks = new Array();
$('#myTable input:checked').each(function() {
allTicks.push($(this).attr('id'));
});
$('#myTable').load('/get-table.jsp', null,
function (responseText,textStatus, req ){
$('#my-table').tablesorter();
//alert(allTicks + ' length ' + allTicks.length);
for (i = 0 ; i < allTicks.length; i++ )
$("#my-table input#" + allTicks[i]).attr('checked', true);
});
}, $refreshInterval);
The id of each checkbox is the same as the table entry next to it.
My idea was to store all the checked checkboxes' ids into an array before the update and to change their values after the update is done, as most of the entries will be preserved, and the ones that are new won't really matter.
'#myTable' is the div in which the table is loaded and '#my-table' is the id of the table which is generated. The checkbox inputs are generated along with the new table and with the same ids as before.
The weird thing is that applying tablesorter to the newly generated table works, but getting the elements with the stored ids doesn't.
Any solutions?
P.S: I know that this approach to table generation isn't really the best, but my JS skills were limited back then. I'd like to keep this solution for now and fix the problem.
EDIT:
Applied the syntax suggested by Didier G. and added some extra test blocks that check the status before and after the checkbox ticking.
Looks like this now:
refreshId = setInterval(function()
{
var allTicks = []
var $myTable = $('#my-table');
allTicks = $myTable.find('input:checked').map(function() { return this.id; });
$('#myTable').load('/get-table.jsp', null,
function (responseText,textStatus, req ){
$myTable = $('#my-table');
$('#my-table').tablesorter();
var msg = 'Before: \n';
$myTable.find('input').each(function(){
msg = msg + this.id + " " + $(this).prop('checked') + '\n';
});
//alert(msg);
//alert(allTicks + ' length ' + allTicks.length);
for (i = 0 ; i < allTicks.length; i++ ){
$myTable.find('#' + allTicks[i]).prop('checked', true);
}
msg = 'After: '
$myTable.find('input').each(function(){
msg = msg + this.id + " " + $(this).prop('checked') + '\n';
});
//alert(msg);
});
}, $refreshInterval);
If I uncomment the alert lines, and check 2 checkboxes, on the next update I get (for 3 row table):
Before: host2 false
host3 false
host4 false
object [Object] length 2
After: host2 false
host3 false
host4 false
Also did a previous check on the contents of the array and it has all the correct entries.
Can the DOM change or working with an entirely new table instance be a cause of this?
EDIT2:
Here's a sample of the table generated by the JSP (edited for confidentiality purposes):
<table id="my-table" class="tablesorter">
<thead>
<tr>
<th>Full Name</th>
<th>IP Address</th>
<th>Role</th>
<th>Job Slots</th>
<th>Status</th>
<th>Management</th>
</tr>
</thead>
<tbody>
<tr>
<td>head</td>
<td>10.20.1.14</td>
<td>H</td>
<td>4</td>
<td>ON</td>
<td>Permanent</td>
</tr>
<tr>
<td>
<input type="checkbox" id="host2" name="host2"/>
host2
</td>
<td>10.20.1.7</td>
<td>C</td>
<td>4</td>
<td>BSTART</td>
<td>Dynamic</td>
</tr>
<tr>
<td><input type="checkbox" id="host3" name="host3"/>
host3</td>
<td>10.20.1.9</td>
<td>C</td>
<td>4</td>
<td>BSTART</td>
<td>Dynamic</td>
</tr>
<tr>
<td><input type="checkbox" id="host4" name="host4"/>
host4</td>
<td>10.20.1.11</td>
<td>C</td>
<td>4</td>
<td>BSTART</td>
<td>Dynamic</td>
</tr>
</tbody>
</table>
Note that the id and name of the checkbox coincide with the host name. Also note that the first td does not have a checkbox. That's the expected behavior.
Changing 'special' attributes like disbaled or checked should be done like this:
$(...).attr('checked','checked');
or this way if you are using jQuery 1.6 or later:
$(...).prop('checked', true); // more reliable
See jQUery doc about .attr() and .prop()
Here's your piece of code modified with a few optimizations (check the comments):
refreshId = setInterval(function()
{
var allTicks = [],
$myTable = $('#myTable'); // select once and re-use
// .map() returns an array which is what you are after
// also never do this: $(this).attr('id').
// 'id' is a property available in javascript and
// in .map() (and in .each()), 'this' is the current DOMElement so simply do:
// this.id
allTicks = $myTable.find('input:checked').map(function() { return this.id; });
$myTable.load('/get-table.jsp', null, function (responseText,textStatus, req ) {
$myTable.tablesorter();
//alert(allTicks + ' length ' + allTicks.length);
for (i = 0 ; i < allTicks.length; i++ )
// avoid prefixing with tagname if you have the ID: input#theId
// #xxx is unique and jquery will use javascript getElementById which is super fast ;-)
$myTable.find('#' + allTicks[i]).prop('checked', true);
});
}, $refreshInterval);
Let us assume that the JavaScript does retrieve and set the checkboxes ticks.
Then there still is a problem with the asynchrone Ajax call.
First try it with a very large $refreshInterval.
Place the for-loop before the tablesorter call.
Do not setInterval, but setTimeout and schedule this for one single time.
Then in the load function schedule the next time.
This prevents overlapping calls which were a possible cause for the error.
But may stop refreshing, when the load is not called. (Not so important.)
After lots of painful hours of digging up every small detail, I realized that my problem was not how I coded the thing, nor was it stuff like unexpected DOM changes, but a simple detail I failed to see:
The id I was trying to assign to the checkbox contained a period (".") character.
This causes lots of problems for jQuery when trying to look up that sort of id, because a period as-is acts as a class descriptor. To avoid this, the period character must be escaped using 2 backslashes.
For example:
$("#my.id") // incorrect
$("#my\\.id") // correct
So then the fix in my case would be:
$myTable.find('#' + allTicks[i].replace(".", "\\.")).prop('checked', true);
... and it finally works.
Thanks everyone for all your helping hands!