Im moving rows between tables, it seems to works fine but once the row is in the other table all javascript functions related to that row no longer work and I have no idea why.
The javascript is pretty straight forward I take the html for the row and move it into the other table.
If you click the child tabs they work fine, but click on waitlist (or approve to move to the table above) to move it to the below table and the tabs for that row no longer work.
The weird thing is no error is thrown, and nothing is logged in the console.
http://jsfiddle.net/Ha3Jq/16/
Jquery
$( ".enrolled-participants" ).on("click","button.remove-participant",function(){
if($(this).hasClass('remove-participant'))
{
$(this).html('Approve');
$(this).removeClass('remove-participant').addClass('add-participant');
var className = $(this).closest('tr').attr('class');
var childClass =$(this).closest('tr').next().attr('class');
var current_row = $(this).closest('tr').html();
var child_row = $(this).closest('tr').next().html();
$(this).closest('tr').next().remove();
$(this).closest('tr').remove();
$('.waitlisted > tbody:last').append('<tr class="'+className+'">'+current_row+'</tr><tr class="'+childClass+'">'+child_row+'</tr>');
}
Im also using the table sorter plugin.
tablesorter
$(".enrolled-participants,.waitlisted")
.tablesorter({
theme : 'blue',
// this is the default setting
cssChildRow: "tablesorter-childRow",
// initialize zebra and filter widgets
widgets: ["zebra", "filter"],
widgetOptions: {
// include child row content while filtering, if true
filter_childRows : true,
// class name applied to filter row and each input
filter_cssFilter : 'tablesorter-filter',
// search from beginning
filter_startsWith : false,
// Set this option to false to make the searches case sensitive
filter_ignoreCase : true
}
});
// hide child rows
//$('.tablesorter-childRow td').hide();
// Toggle child row content (td), not hiding the row since we are using rowspan
// Using delegate because the pager plugin rebuilds the table after each page change
// "delegate" works in jQuery 1.4.2+; use "live" back to v1.3; for older jQuery - SOL
$('.tablesorter').delegate('.toggle', 'click' ,function(){
//alert('ok');
// use "nextUntil" to toggle multiple child rows
// toggle table cells instead of the row
$(this).closest('tr').nextUntil('tr:not(.tablesorter-childRow)').find('td').toggle();
return false;
});
// Toggle widgetFilterChildRows option
$('button.toggle-option').click(function(){
var c = $('.tablesorter')[0].config.widgetOptions,
o = !c.filter_childRows;
c.filter_childRows = o;
$('.state').html(o.toString());
// update filter; include false parameter to force a new search
$('input.tablesorter-filter').trigger('search', false);
return false;
});
Use detach instead of remove.
remove removes it from the DOM, and it removes all of the (JavaScript) event listeners.
detach simply removes it from the DOM; the event listeners are left intact.
Related
I'm using DataTable API and jquery to construct a table after getting its rows from the server. Then I press the btn to load other rows and add the to the end of the table. The trouble is when I hide certain columns: the initial rows get rid of triggered columns but those which are loaded later aren't affected by filters. How to fix this? After research I found out that when filtering the function gets all the rows not the initial ones.
var data = $(this).dataTable().toArray();
if ($this.prop("checked") === false) {
data.forEach(function (element) {
$(element).DataTable().columns().column(column).visible(false);
});
} else {
data.forEach(function (element) {
$(element).DataTable().columns().column(column).visible(true);
});
}
Loading the remaining rows
var tbody = $("#tbody-" + $this.attr("data-parent-id"));
var dt = tbody.parents(".bizon-datatable").DataTable();
$(result).filter("tr").each(function (i, v) {
dt.row.add($(v));
});
tbody.append(result);
The key is understanding that each executes against the set of items that are found at the moment that selector runs. So if you have 10 rows initially and each executes, it will apply to 10 rows, and any added later will not have the conditions applied by each.
The same goes for filter. It applies to the elements that are returned by the selector at the time the selector executes--not to anything added later. The selector only selects DOM elements that match at the moment it runs and doesn't apply to any future DOM elements that are added. So you have to re-select DOM elements after you've added elements if you want to apply filters or other conditions to all current DOM elements.
To fix this, you would need to re-apply the filter after adding rows or re-run the each if you have added rows.
How to tell to jQuery tabledit that the rows are changed? The buttons only generated for existing rows, when I add a new row (for example using jQuery), the table buttons doesn’t appear in the new row. I saw in tabledit code, that there is possibility to switch between view and edit mode (maybe this would help me), but don’t know how to access these methods after the tabledit is created and when rows has been changed.
A little snippet from my code:
$(document).ready(function(){
$(‘#btn’).click(function(){ ... adding row, I need to update tabledit here });
$(‘#table’).Tabledit(...parameters...); }
});
tabledit
Here is the best solution I could come up with for your situation.
I created an "Add" button. NOTE the for-table attribute so I can figure out what table to add to later.
<button id='add' for-table='#example1'>Add Row</button>
Then I created a click handler for the "Add" button.
$("#add").click(function(e){
var table = $(this).attr('for-table'); //get the target table selector
var $tr = $(table + ">tbody>tr:last-child").clone(true, true); //clone the last row
var nextID = parseInt($tr.find("input.tabledit-identifier").val()) + 1; //get the ID and add one.
$tr.find("input.tabledit-identifier").val(nextID); //set the row identifier
$tr.find("span.tabledit-identifier").text(nextID); //set the row identifier
$(table + ">tbody").append($tr); //add the row to the table
$tr.find(".tabledit-edit-button").click(); //pretend to click the edit button
$tr.find("input:not([type=hidden]), select").val(""); //wipe out the inputs.
});
Essentially;
Deep Clone the last row of the table. (copies the data and attached events)
Determine and set the row identifier.
Append the new row.
Automatically click the Edit button.
Clear all inputs and selects.
In my limited testing this technique appears to work.
jQuery Tabledit should be executed every time a table is reloaded. See answer given here:
refreshing Tabledit after pagination
This means that every time you reload the table (e.g. navigating to new page, refreshing etc), you must initialize Tabledit on the page of the table where it wasn't initialized. The problem is that there is no way to know whether Tabledit has been initialized on the table already, hence if you re-initialize it, duplicate buttons (edit, delete..) will be added to the rows of the table. You also cannot destroy a non-existent Tabledit, hence calling 'destroy' always beforehand will not help.
I hence created my own function to tell me if Tabledit is initialized on a certain page of a table or not:
function hasTabledit($table) {
return $('tbody tr:first td:last > div', $table).hasClass("tabledit-toolbar");
}
and using it as follows:
if( !hasTabledit($('#table')) ) {
$('#table').Tabledit({
url: 'example.php',
columns: {
identifier: [0, 'id'],
editable: [[1, 'points'], [2, 'notes']]
},
editButton: true,
deleteButton: false
});
}
The hasTabledit(..) function checks whether the last cell of the first row of the table has a div which has the tabledit-toolbar class, since this is the div that holds the Tabledit buttons. You may improve it as you like. This is not the perfect solution but it is the best I could do.
I have to change in one function, after the initialization of a datatable, bSearchable property of a column. I need first to enable and then disable it.
I found an example for visibility:
$(document).ready(function() {
var table = $('#example').DataTable( {
"scrollY": "200px",
"paging": false
} );
$('a.toggle-vis').on( 'click', function (e) {
e.preventDefault();
// Get the column API object
var column = table.column( $(this).attr('data-column') );
// Toggle the visibility
column.visible( ! column.visible() );
} );
} );
Can something similar be used also in my case? Something like column.seachable?
This is an old question, but one that cost me several hours to research the answer to... mostly based on my lack of JS skill though.
The usecase was that I have a table with an ID column that is a GUID. This Id is seldom used uses a lot of space, so it's hidden and not searchable by default. But for internal users who might have access to logs or the database, we need to be able to search the ID column as well.
I added a checkbox for these users and it should change visibility and the searchable attribute of the ID column.
My solution is based on another question regarding searching on columns. But in this question, the search was only intended on one single column and not on all searchable columns as well (normal DataTable.search() API). Sadly, to change the searchable property, there seems to be no public API. If you change the searchable property, you have to invalidate the data in the table afterwards, otherwise the columns data will still be / not be present in the tables aoFilterData. This forces the table to reload the data from the datasource (in this case, the DOM).
I had a lot of problems with registering the eventhandlers at the right place. The filter field is not present at the first draw event of the table, so i had to register the handlers in the init event that is fired after the table is fully initialized.
var userTable;
var idSearchCbx;
var searchField;
$(document).ready(function () {
userTable = document.getElementById("table-users");
if (userTable) {
userTable = $("#table-users").DataTable(
{
"columnDefs": [
{
//First column invisible and not searchable by default
"targets": [0], //first column = ID
"visible": false,
"searchable": false
}],
//Other initialization options
); //Table creation
userTable.on("init",
function () {
$("input[type='search']").on("change cut input keypress keyup paste search recheck",
function () {
var searchValue = $(this).val();
userTable.search(searchValue).draw();
//width attribute is calculated and added to the table
//it loses 2 pixels everytime the checkbox is checked/
//unchecked somehow - so delete it
document.getElementById("table-users").removeAttribute("style");
});
idSearchCbx = $("#cbx-search-id");
idSearchCbx.on("change",
function () {
if (this.checked === true) {
//this makes the first column searchable, not official API
userTable.context[0].aoColumns[0].bSearchable = true;
//make it visible as well, official API
userTable.columns(0).visible(true);
//invalidates cached table data so that the column values are
//added to the filterdata
userTable.rows().invalidate().draw();
} else {
userTable.context[0].aoColumns[0].bSearchable = false;
userTable.columns(0).visible(false);
userTable.rows().invalidate().draw();
}
//trigger the normal search again so that the
//filter is / is not applied to the first column
$("input[type='search']").trigger("recheck");
});
}); //DT on init
} //table present
});//document ready
I assume context is related to settings(), so keep in mind that names in the context might change and this is most likely not version-stable even in minor releases. But I didn't find any other way. Hope it helps someone.
I'm trying to create a table of inputs that automatically adds a new row when you enter text in one of the inputs on the bottom line. For the most part, it works fine. However, I'm having some trouble with jQuery UI checkbox buttons.
The checkbox buttons are supposed to change their icon when clicked. This works fine for the original buttons, but the cloned button that appears when you add a new row doesn't work properly.
You can see it in jsfiddle here. To replicate the issue, put some text in the third input down. You'll see that a fourth row appears. If you press the fourth checkbox, you'll see the third checkbox is the one whose icon changes. The wrong button also gets ui-state-focus but doesn't actually get focus, which really baffles me, though the correct button does get ui-state-active and seems, as far as I can tell, to evaluate as having been checked properly.
To be clear, the two checkboxes do not have the same ID, and their labels are for the right checkbox - the createNewRow() function takes care of that. If you comment out the line that turns the checkboxes into jQuery UI checkboxes, you'll see everything works fine. If you console.log the value of $(this).attr('id') in the buttonSwitchCheck function, you'll see that it has the right ID there too - if you click the fourth button, it'll tell you that the id of $(this) is "test4", but it's "test3" (the third button) that gets the icon change.
I'm going mad staring at this and I'd appreciate any help people can give. Here's the code:
// Turns on and off an icon as the checkbox changes from checked to unchecked.
function buttonSwitchCheck() {
if ($(this).prop('checked') === true) {
$(this).button("option", "icons", {
primary: "ui-icon-circle-check"
});
} else {
$(this).button("option", "icons", {
primary: "ui-icon-circle-close"
});
}
}
// Add a new row at the bottom once the user starts filling out the bottom blank row.
function createNewRow() {
// Identify the row and clone it, including the bound events.
var row = $(this).closest("tr");
var table = row.closest("table");
var newRow = row.clone(true);
// Set all values (except for buttons) to blank for the new row.
newRow.find('.ssheet').not('.button').val('');
// Find elements that require an ID (mostly elements with labels like checkboxes) and increment the ID.
newRow.find('.ssheetRowId').each(function () {
var idArr = $(this).attr('id').match(/^(.*?)([0-9]*)$/);
var idNum = idArr[2] - 0 + 1;
var newId = idArr[1] + idNum;
$(this).attr('id', newId);
$(this).siblings('label.ssheetGetRowId').attr('for', newId);
});
// Add the row to the table.
newRow.appendTo(table);
// Remove the old row's ability to create a new row.
row.removeClass('ssheetNewRow');
row.find(".ssheet").unbind('change', createNewRow);
}
$(document).ready(function () {
// Activate jQuery UI checkboxes.
$(".checkButton").button().bind('change', buttonSwitchCheck).each(buttonSwitchCheck);
// When text is entered on the bottom row, add a new row.
$(".ssheetNewRow").find(".ssheet").not('.checkButton').bind('change', createNewRow);
});
EDIT: I was able to find a solution, which I'll share with the ages. Thanks to "Funky Dude" below, who inspired me to start thinking along the right track.
The trick is to destroy the jQuery UI button in the original row before the clone, then reinitializing it immediately afterwards for both the original row and the copy. You don't need to unbind and rebind the change event - it's just the jQuery UI buttons which have trouble. In the createNewRow function:
row.find('.checkButton').button('destroy');
var newRow = row.clone(true);
row.find('.checkButton').add(newRow.find('.checkButton')).button().each(buttonSwitchCheck);
Try using the newer method .on, that allows for delegation, which should help with the dynamic changes to your DOM:
$(".checkButton").button().each(buttonSwitchCheck);
$("table").on("change", ".checkButton", buttonSwitchCheck);
I'm not sure, but it might help with not having to worry about binding events to specific elements.
Also, you could use it for the textbox change event:
$("table").on("change", ".ssheetNewRow .ssheet:not(.checkButton)", createNewRow);
Here's your fiddle with my changes: http://jsfiddle.net/Cugb6/3/
It doesn't function any different, but to me, it's a little cleaner. I thought it would've fixed your problem, but obviously hasn't, due to problems with the button widget.
And funny enough, it doesn't seem they "support" cloning: http://bugs.jqueryui.com/ticket/7959
i think you are using deep clone, which also clones the event handler. in your create new row function, try unbinding the change event then rebind on the clone.
I am working with some custom ajax functionality using Telerik's MVC Grid and I am trying to hide/remove child elements of a cell based on specific criteria, I found a similar question here: Telerik MVC Grid making a Column Red Color based on Other Column Value but couldn't get it working right.
Basically when the row is databound in the grid this event fires:
function onRowDataBound(e) {
if (e.dataItem.Status == "Submitted") {
$.each(e.row.cells, function (index, column) {
alert(column.innerHTML);
//var $header = $(column).closest('table').find('th').eq($(column).index());
//if(header text == "Actions)
//{
//Get the <a> child elements in the 'Actions' column whose class contains t-grid-Edit,
//t-grid-edit, t-grid-Delete, or t-grid-delete and set their display to none, add a css class, and remove the element entirely
//}
}
}
}
So far it's working in that I can get and iterate through each column in the row, but I am not sure what to do at this point, I found this How can I get the corresponding table header (th) from a table cell (td)? to check to make sure the column name name is Actions, but I couldn't get it working. I am not sure how to convert the javascript HTMLTableCellElement object into a jQuery object so I can use syntax I am more familiar with.
Here is what I need to do after that:
Get the child elements in the 'Actions' (has to go by column header name instead of cell index because the number of columns can change) column whose class
contains t-grid-Edit, t-grid-edit, t-grid-Delete, or t-grid-delete
Take those elements and (each of these actions would be used on different pages using similar setups):
a. Set the element's display style to none
b. Add a class to the element of name "Hidden"
c. Remove the element from the code entirely
How can I put the above functionality into my onRowDataBound function?
Thank you SO =).
I was able to figure this out with a lot of playing:
function onRowDataBound(e) {
if(e.dataItem.Status == "Submitted"){
var $row = $(e.row);
$.each($row.children("td"), function (index, column) {
var $column = $(column);
var $headerText = $column.closest('table').find('th').eq($column.index()).children(".t-link").text();
if ($headerText == "Actions") {
$.each($column.children("a.t-grid-delete, a.t-grid-Edit"), function (subIndex, link) {
$(link).remove();
});
}
});
}
}