TableDnD onDrop event not firing - javascript

I'm sure this is something very simple, it usually is.
$('#sort-table').tableDnD({
onDragClass: "dnd_drag",
onDragStart: function(table, row) {
console.log("start drag");
},
onDrop: function(table, row) {
console.log($.tableDnD.serialize());
},
dragHandle: ".dragHandle"
});
I have the above code in action for tableDnD, the jQuery table sorting plugin. This is the exact code from the samples they provide, but it doesn't fire the onDrop event correctly when I drop an item in the table. I get no response in the console. The table does initialize, and the drag handle works properly, so I at least know that portion of the code is correct. The only thing I can't get to work is the onDrop command.
Update:
I updated the code above to add an onDragStart and onDragClass, both of which work perfect, it is only the onDrop function failing.
This is my general table layout:
<table id="sort-table">
<tbody class="sort-items">
<tr class="1">
<td class="dragHandle"></td>
...
</tr>
...
</tbody>
</table>

You must define tr[id] attribute to make onDrop work.
This is because onDrop only fire when row order changed.
However, without specifying tr[id] attribute, tableDnD.serialize() will think there was not any re-order. (Bug for sure)

Well my first question and I got the answer to it. Hope this helps someone in the future.
The issue was with the actual ID's of my table rows. I actually had use of uuid which meant that my rows actually had an ID similar to "26b5122e-bbb8-11e1-9c53-d4856404b576". Apparently TableDnD does some sort of serializing of the data that broke my ID's apart and only grabbed the last group of numbers, which for most items were the same.
The line from the jquery.tablednd.js file that was causing the issue was this (around line 380):
...
var rowId = rows[i].id;
if (rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {
rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];
}
result += tableId + '[]=' + rowId;
...
I simply removed the serializer since I knew I wouldn't need it for my row IDs. Then I passed the row ID along myself. This was the result.
...
var rowId = rows[i].id;
result += tableId + '[]=' + rows[i].id;
...
So if you use dashes in your row IDs, make sure to change this to make the onDrop fire correctly.

Quick fix.
If you want onDrop to work without having row.id, you can edit plugin.
Replace this (line 255 is where function starts - currentOrder)
var rows = this.currentTable.rows;
return $.map(rows, function (val) {
return ($(val).data('level') + val.id).replace(/\s/g, '');
}).join('');
With this
return $(this.dragObject).index();

Related

How does DataTable drawCallback work?

I am trying to apply CSS to each of the DataTable cells based on its value, using the drawCallback().The CSS gets applied to a few cells and not all. Here is the JsFiddle to my issue.Has anyone come across this issue and found a solution or have any ideas on this.Please suggest!
"drawCallback": function( settings ) {
var api = this.api();
var visibleRows=api.rows( {page:'current'} ).data();
if(visibleRows.length >= 1){
for(var j=1;j<visibleRows[visibleRows.length -1].length;j++){
$("td:eq("+j+")", settings.nTBody.childNodes[visibleRows.length -1]).addClass(visibleRows[visibleRows.length -1][j]);
}
}
},
Like #charlietfl said, you don't really want to be using drawCallback to format the rows, and you would probably be better off using createdRow (rowCallback) to do this formatting.
drawCallback is called on every draw event, meaning that it's really meant to be used to update rows that have just been added or work with data that has just been updated.
createdRow on the other hand, is designed to be called whenever a row is created, which seems to be what you really want. In this documentation (example), you can see that the author displays how to use this option to add a class to certain rows, which seems to be the closest to what you want to do.
As far as I can tell, you want to make every cell have a CSS class that is the same as the text in the cell (correct me if I'm wrong). The easiest way to do that with createdRow would be as follows:
"createdRow": function ( row, data, index ) {
for(var i = 0;i<data.length;i++){
$('td', row).eq(i).addClass(data[i]);
//The above line assumes that you want to add a CSS class named "red" to a
//field that has the text "red" in it, if not, you can change the logic
}
}
Just include this in your initialization options for the .DataTables() call.
I had to make some assumptions about the exact logic for what classes get added to what columns, but if they are correct, then this should add a class to each field that is named the same as the text in that field.

jQuery need help selecting tr elements inside a div element with a specific class

I'm trying to build a custom hover event using Kendo UI Grid control. I'm having issues getting the entire row to highlight on mouseover when using locked columns. I have not been able to find a straightforward example to follow.
Currently the selection on hover looks like this:
I've written the following function to try and highlight the entire row (locked and unlocked sections) but I can't seem to get the correct jQuery selector:
$("#ddhintgrid div.k-grid-content table tbody tr").hover(function () {
//stuff to do on mouse enter
var grid = $("#ddhintgrid").data("kendoGrid");
var rowUid = grid.dataItem(this).uid;
// select the row currently being edited
$('[data-uid=' +rowUid + ']').addClass('k-state-hover');
},
function () {
//stuff to do on mouse leave
$("#ddhintgrid .k-state-hover").removeClass("k-state-hover");
});
The contents of this method is unimportant. I simply want it to trigger when the user moves the mouse over a row in the unlocked portion of the grid.
The element I want the .hover() function to fire on is the tr element under the <div class="k-grid-content> element. See here:
I found the answer by modifying the solution found here: Add jQuery hover effect across two tables.
I added the following code to dataBound function of the dataSource for my grid:
var $trs = $('table.k-selectable tbody tr');
$trs.hover(
function () {
var i = $(this).index() +1;
$trs.filter(':nth-child(' +i + ')').addClass('k-state-hover');
},
function () {
var i = $(this).index() +1;
$trs.filter(':nth-child(' +i + ')').removeClass('k-state-hover');
}
);
Hopefully this helps anyone else having this issue. Haven't noticed any problems yet.
Try
$("#ddhintgrid > .k-grid-content > table > tbody > tr:not(:first, :last)").hover(function () {...});
You need to exclude the first and last (header and footer) tr's.
Also, you will need to iterate through the opposite table to find the associated row in order to set the CSS to "k-state-hover"/
Example:
I hover over row1 in the locked table, now the function should set the css for locked table row1 and find row1 in the "k-grid-content" table and also set the css for that row. The two rows will have different UID's so you can't rely on that for comparison, try n'th child or if you have a unique key for the rows data then you can use that to compare them.
In order to properly have the effect on sort etc. this has to be done in the dataBound event on the grid OR should be able to do it client side. I did not test these but it should work.
Client bound
You need to add a function to use toggling the class:
addHoverStyleToGridRow = function () {
$("table.k-focusable tbody tr").hover(function() {
$(this).toggleClass("k-state-hover");
}
);
};
Then in the data bound:
// this is where the hover effect function is bound to grid
$("#ddhintgrid").kendoGrid({ dataBound: addHoverStyleToGridRow });
Server bound
On the chance you are using server bound grid then this:
$(document).ready(function() {
$("#ddhintgrid").find("table.k-focusable tbody tr").hover(function() {
$(this).toggleClass("k-state-hover");
}
);
});

How to get td values from dynamically created table

I see a lot of similar questions but not one that directly targets my problem. The business logic of my problem is that I allow the user to open a jQuery Dialog where I create table loaded with a data from a database and when the user make a choise I load the selected data info fields from the main screen.
My current problem is with collecting the data from the <tr> which happens on button click. If it was a hard coded table I would just:
$(selector).on('click', function(){
var $item = $(this).closest("tr").find('td');
})
and then do something with $item however the table is created dynamically (from Ajax request) everytime the Ajax request is made the table is destroyed and recreated so basically I can't or at least I don't know a way to use some sort of selector to which to bind the event so I can reproduce the above code.
Instead in the dynamic table I have this:
<td><button onclick="getData();return false">Select</button>
The problems with this (at least how I see it) are two - first, the using of onclick inside HTML element. From what I know it's not a good practice and there are better alternatives and I would appreciate answer showing this. Also, even though I go with this code I'm yet unable to extract the text from each <td> in:
function getData() {
...
}
I tried several approaches including the one which was working with the static table and the binded event handler.
At the end here is a JS Fiddle example where I think I made it clear what I can and what I can not do, so you can refer to it.
Check this fiddle
$(selector).on('click', function(){
var $item = $(this).closest("tr").find('td');
})
Using the above code you are binding a direct event but the one which you want is delegated event
To use delegated event you should use like
$(document).on('click',selector, function(){
var $item = $(this).closest("tr").find('td');
})
so your final code will look something like
$(document).on('click','.get-data' ,function(){
var $item = $(this).closest("tr").find('td');
$.each($item, function(key, value){
alert($(value).text());
})
});
document can be anything which is parent to the table which is going to be created.
Dont forget to add the selector while adding a new table element
I had the same problem and solved it that way.
You can create your table with the database results like this:
for (var i = 0; i < results.length; i++) {
// create table row and append it to the table using JQuery
// next create a td element, append it to the created tr
// and attach a listener to it
$('<td/>').html(results[i].textProperty)
.appendTo($(tr))
.on('click', getData);
}
where getData() is your function.
You can pass arguments to your getData like this:
.on('click', {info: results[i].data}, getData);
Then you can access them in your function:
function getData(event) {
console.log(event.data.info);
}
Hope this helps!
Edit: This way you are creating a listener for each td. An optimization could be to create a listener for the whole class of td elements and to pass data to it via HTML attributes or text value like in the approved answer.
or you can use this pass object in getdata method
$('#build-table').on('click', function(){
$('#temp-table').append('<table><thead><tr><th>Select</th><th>Name</th> </tr></thead>' +
'<tbody><tr><td><button class onclick="getData(this);return false">Select</button></td><td>Name1</td></tr>' +
'<tbody><tr><td><button onclick="getData(this);return false">Select</button></td><td>Name2</td></tr>' +
'</tbody></table>')
});
function getData(ob) {
var $item = $(ob).closest("tr").find('td');
$.each($item, function(key, value){
alert($(value).text());
})
}

Javascript get the text value of a column from a particular row of an html table

A user clicks on a row of a table, and I want to get (in Javascript) the innerhtml of let's say the 3rd column of that row.
Something like :
document.getElementById("tblBlah").rows[i].columns[j].innerHTML
doesn't seem achievable and I can't find anything here or in the net.
Any solutions would be very much appreciated ( NO jQuery )
document.getElementById("tblBlah").rows[i].columns[j].innerHTML;
Should be:
document.getElementById("tblBlah").rows[i].cells[j].innerHTML;
But I get the distinct impression that the row/cell you need is the one clicked by the user. If so, the simplest way to achieve this would be attaching an event to the cells in your table:
function alertInnerHTML(e)
{
e = e || window.event;//IE
alert(this.innerHTML);
}
var theTbl = document.getElementById('tblBlah');
for(var i=0;i<theTbl.length;i++)
{
for(var j=0;j<theTbl.rows[i].cells.length;j++)
{
theTbl.rows[i].cells[j].onclick = alertInnerHTML;
}
}
That makes all table cells clickable, and alert it's innerHTML. The event object will be passed to the alertInnerHTML function, in which the this object will be a reference to the cell that was clicked. The event object offers you tons of neat tricks on how you want the click event to behave if, say, there's a link in the cell that was clicked, but I suggest checking the MDN and MSDN (for the window.event object)
in case if your table has tbody
let tbl = document.getElementById("tbl").getElementsByTagName('tbody')[0];
console.log(tbl.rows[0].cells[0].innerHTML)
To get html code :
document.getElementById("table").rows[i].cells[j].innerHTML;
To get text :
document.getElementById("table").rows[i].cells[j].innerText;

Manipulating row data with Javascript

I have a specific question, I have a link in a table in the third column of each row, when the user clicks that link he loads some ajax and updates the page, what I want to also happen is that in the 2nd column of the row where the link is, change the td's class from false to true, and the value from No to Yes.
Thanks!
Update!
Code Example:
The 2nd column still doesn't get updated on click, perhaps this is because the div where the table is located gets hidden onclick? Anyways here's what I've tried:
<tr>
<td>00839</td>
<td class="false" style="text-align:left;">No</td>
<td>
<a href="#"
onclick="Element.hide('ajax-instruction-view');;
new Ajax.Updater('ajax-instruction-view', '/tasks/show_ajax/839', {asynchronous:true, evalScripts:true, onComplete:function(request){new Effect.Appear("ajax-instruction-view",{});window.scrollTo(0,0);
link = $(link);
var row = link.up('tr');
var cell = row.down('td').next('td');
cell.update('Yes');},
parameters: 'authenticity_token='encodeURIComponent('SYWsdBTWlz17u9HmPXA2R9WmBfZn67g/IAMGyhHEwXw=')}); return false;"
>
Instructions-Notice Board
</a>
</td>
<td>19/04/10</td>
<td class="false">21/04/10</td>
<td class="false" style="text-align:left;">None.</td>
</tr>
It sounds as though at some point, you have a reference to the link the user clicked (either because you have a click handler on it or because you're using event delegation and finding it after a click on the table). Starting with a reference to that link, you can use Prototype's DOM traversal stuff to find the second table cell:
Edit Based on your response to rahul, I would change your link onclick to:
onclick="handleLinkClick(this); return false;"
...and this would be handleLinkClick:
function handleLinkClick(link) {
// Original code (mostly unchanged)
Element.hide('currentdiv');
new Ajax.Updater('someajax', 'ajax.html', {
asynchronous:true,
evalScripts:true,
onComplete: function(request) {
new Effect.Appear("newdiv",{});
window.scrollTo(0,0);
// New code starts here
// Extend the link element
link = $(link);
// Find the row
var row = link.up('tr');
// Find the second column
var cell = row.down('td').next('td');
// Change the cell's "class" and "value" -- I've had to guess a bit at
// what you want to do here
if (cell.hasClassName("true")) {
cell.removeClassName("true").addClassName("false");
cell.update("No");
}
else {
cell.removeClassName("false").addClassName("true");
cell.update("Yes");
}
// End of new code
},
parameters:'authenticity_token=' + encodeURIComponent('SYWsdBTWlz17u9HmPXA2R9WmBfZn67g/IAMGyhHEwXw=')
});
}
That uses Element#up, Element#next, Element#hasClassName, Element#addClassName, Element#removeClassName, and Element#update; docs for them here.
Optional things to consider:
The above is fragile in that if you change the location of that cell (make it the third column rather than the second), it fails. You might use a marker class to find it.
Rather than an onclick attribute, you could use Element#observe.
You can use event delegation to have just one handler on the table, rather than a handler on each link.
But the above should work.
I dont recall how to write it in Scriptaculous but in jQuery it would be:
$(element).click(function(){
// invoke your ajax routine
// change class
$($(this).parent('tr').children().get(1)).attr('class', 'my-classname');
});
Maybe someone can translate :-)

Categories