I have implemented a JQuery bootgrid. My problem is that I want to ignore the row click event for when a select input in my bootgrid is clicked.
This is what I have so far:
.on("click.rs.jquery.bootgrid", function (e, columns, row, target) {;
if(/* Clicked element is not a select input */) {
location.href = "/row?id=" + row.Id;
}
});
Any idea how to accomplish this? I've been struggling around with this for ages now.
Edit: Why Alisson's answer doesn't work.
When I do this:
.on("click.rs.jquery.bootgrid", function (e, column, row, target) {
console.log(row.IncidentId);
});
I can get the IncidentId, but when I do this:
.on("loaded.rs.jquery.bootgrid", function () {
grid.find(".some-selector").on("click", function (e) {
// do what you need here...
var IncidentId = $(this).closest('tr').data('IncidentId');
location.href = "/row?id=" + IncidentId;
});
});
It doesn't work because I can't access the IncidentId that way.
This is my <thead>:
<thead>
<tr>
#*<th data-column-id="IncidentId" data-visible="false">Id</th>*#
<th data-column-id="CaseNumber" data-order="asc">Case Number</th>
<th data-column-id="Title">Case Title</th>
<th data-column-id="EntrepreneurContact">Entrepreneur Contact</th>
<th data-column-id="Mentor">Mentor</th>
<th data-column-id="StatusReason">Status Reason</th>
<th data-column-id="CreatedOn">Created On</th>
</tr>
</thead>
I want this:
Not this:
Edit: a better solution
You can use the click event as you would, but combining with the loaded event to stop the propagation of your select input events like so:
var bootgrid = $("#grid1").bootgrid(config);
bootgrid.on("click.rs.jquery.bootgrid", function (e, columns, row, target) {
console.log('Incident Id: ' + row.IncidentId);
});
bootgrid.on("loaded.rs.jquery.bootgrid", function (e, c, rows) {
// avoid any element with "stop-click-event" class from triggering the event in the grid...
$(".stop-click-event").click(function(e) {
e.preventDefault();
e.stopPropagation();
});
});
You need to bind to click inside the loaded event of the grid, because this is where you are sure the elements like your select input already exist in the DOM, and since after each reload of the grid (at least for ajax calls) the bootgrid delete all your elements and recreate with new data, loaded will be triggered again, so these new elements will be bound again.
Here is a working JSFiddle
Old solution
Instead of using this click.rs.jquery.bootgrid event, bind to loaded, and once loaded, bind to the correct elements you need:
var grid = $("#my-grid").bootgrid(config)
.on("loaded.rs.jquery.bootgrid", function () {
// find elements inside the grid, using some jQuery selector...
grid.find(".some-selector").on("click", function (e) {
// do what you need here...
var rowId = $(this).closest('tr').data('row-id');
location.href = "/row?id=" + rowId;
});
});
If you still need to add a listener to an entire row, for example, and want to avoid a click in a button or an input, you can do something like this (still inside loaded event):
// bind to all rows inside the grid...
grid.find("tr").mouseup(function (e) {
// do something
var rowId = $(this).data('row-id');
location.href = "/row?id=" + rowId;
});
// avoid when clicking any "a", "input" or "button" tags...
grid.find("tr td a, tr td input, tr td button").mouseup(function (e) {
e.stopPropagation();
});
Related
I have a table in ASP MVC where a user can make changes to several fields within a row which are dropdown menus. Once the changes are made and user removes focus from that row I want to call AJAX to save changes. My problem is that the AJAX call is made for every single change that is made, so many calls for a single row.
//JQUERY
$(function () {
$(".payroll").on('change',function (e) {
var ctrl = $(this).closest('tr');
var empID = ctrl.find("td:first").html();
var employeeLine1 = ctrl.find("td:nth-child(2)").html();
var employeeLine2 = $.trim(ctrl.find("td:nth-child(3) span").html());
updatepayroll(empID, employeeLine1, employeeLine2, ctrl);
});
updatepayrollReallocation = function (empID, employeeLine1, employeeLine2, ctrl) {
$.ajax({
//Update changes
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<tr>
<td id="payrollID">1</td>
<td>#Html.DropDownListFor(modelItem => item.employeeLine,(SelectList)ViewBag.employeeLineHeaders,
item.employeeLine, new { #class = "payroll", #data_width = "fit" })
</td>
<td>#Html.DropDownListFor(modelItem => item.employeeLine2,(SelectList)ViewBag.employeeLine2Headers,
item.employeeLine2, new { #class = "payroll", #data_width = "fit" })
</td>
</tr>
If you want to send callback when any controls inside a row lost its focus, use focusout event handling against table row like this (assumed PayrollGrid is the <table> ID set by id attribute):
$("#PayrollGrid").on('focusout', 'td', function () {
$.ajax({
// do something with AJAX callback
});
});
If you want to trigger AJAX based on focus of DropDownListFor helpers, use payroll class instead:
$("#PayrollGrid").on('focusout', '.payroll', function () {
$.ajax({
// do something with AJAX callback
});
});
Also note that you may try to declare empID, employeeLine1, employeeLine2 and ctrl variables outside the scope, then assign it inside change event handling and pass it to AJAX callback when focusout event is triggered.
I'm using Datatables to sort / filter a table of data I have. I'd like to be able to sort and filter both in the header, however, the click to filter makes the table sort and the filter select then does not stay open.
I have a demo here: http://codepen.io/jasonflaherty/pen/xOdqVV using this type of idea:
<thead>
<tr>
<th><span class="header">Name</span><span class="filter"></span></th>
<th><span class="header">Position</span><span class="filter"></span></th>
<th><span class="header">Office</span><span class="filter"></span></th>
<th><span class="header">Age</span><span class="filter"></span></th>
<th><span class="header">Start date</span><span class="filter"></span></th>
<th><span class="header">Salary</span><span class="filter"></span></th>
</tr>
</thead>
Is there a way to take the bSort click off the entire th element and make it just work on a class="header" for example?
You can use .off function to remove the click event from <th> tag. Then add new event handler to the element which you want to, in that event handler, you can call DataTables API columns().order().
Base on your code, added this after append options to select:
// your code
column.data().unique().sort().each(function(d, j) {
select.append('<option value="' + d + '">' + d + '</option>')
});
// new code here
// remove original event handler
$(column.header()).off('click');
// register new event handler
$(column.header()).on('click', function(e) {
// check click target is "<span class='header'>...</span>" or not
if (e.target.nodeName !== 'SPAN' || !$(e.target).hasClass('header'))
return;
// call DataTables API to sort this column and redraw this table
column
.order($(this).hasClass('sorting_desc') ? 'asc' : 'desc')
.draw();
});
Note: if you just want the <select> tag do not trigger sort event. you can add a click event handler to <select> element to stop event bubbling.
For example:
var select = $('<select><option value=""></option></select>')
.appendTo($(column.header()).find('span.filter').empty())
.on({
'change': function() {
// Do something
},
'click': function(e) {
// stop click event bubbling
e.stopPropagation();
}
});
Hope this is useful.
I have two Gridviews, one loaded with data and the other not. When I double click an item from gvDisplayAvailItems, I want the row to go to gvDisplaySelectedItems, and vice-versa. The Grids are also multi-select, with a button allowing all selected items to be moved. gvDisplaySelectedItems differs by 1 additional input column.
AddDisplayParams() is called when the button is pressed.
function AddDisplayParams() {
var rows = $("#gvDisplayAvailItems").find('tr.selected');
rows.each(function (index, element) {
element.classList.remove("selected");
var newRow = element.cloneNode(true);
newRow.appendChild(customIdTb.cloneNode(true));
$("#gvDisplaySelectedItems").append(newRow);
element.remove();
});
}
AddDisplayParam is called on double-click.
function AddDisplayParam(param) {
var newRow = param.clone(true);
newRow.append(customIdTb.cloneNode(true));
$("#gvDisplaySelectedItems").append(newRow);
param.remove();
}
And here is how I trigger the selection and double clicks.
$("#gvDisplaySelectedItems tr").click(function () {
$(this).toggleClass("selected");
});
$("#gvDisplaySelectedItems tr").dblclick(function () {
RemoveDisplayParam($(this));
});
$("#gvDisplayAvailItems tr").click(function () {
$(this).toggleClass("selected");
});
$("#gvDisplayAvailItems tr").dblclick(function () {
AddDisplayParam($(this));
});
When I both double click and mass select rows on gvDisplayAvailItems, the rows are moved to gvDisplaySelectedItems correctly. However, nothing is triggered for the functions of gvDisplaySelectedItems for rows that were added via AddDisplayParams. Those added by AddDisplayParam can be highligted, but when double clicked only append another textbox to the row in gvDisplaySelectedItems.
So it seems that .clone and .cloneNode are doing something very different here despite having basically the same function. Could someone please explain why one partially works, while the other does not? And also, why my functions for the second grid are not triggered upon single and double click?
I'd suggest to try delegated event handlers.
E.g.
$("#gvDisplaySelectedItems").on("click", "tr", function () {
$(this).toggleClass("selected");
});
instead of
$("#gvDisplaySelectedItems tr").click(function () {
$(this).toggleClass("selected");
});
and so on for other event handlers.
More info
Regarding other improvements - you don't have to clone()/append()/remove() to move an element. Just doing append() to a new parent will effectively move it since an element can have only one parent each moment of time.
Example: JSFiddle
I am currently using this code for row click event in a bootstrap table
$('#myTable').bootstrapTable().on('click-row.bs.table', function (e, row, $element)
{
//....my operation
}
The problem is this triggers for the entire row and I want to be able to trigger it for a single cell.
Note I am using the arguments, row and $element
Here is the FIDDLE
$element is the entire row, you cannot know what cell have been clicked by this way,
bootstrap table do not have cell click event, so you need manually add click event on last cell and fill your needed vars yourself
$('#table').bootstrapTable({
data: data
}).on('click','td:last-child',function(){
var $t = $(this), $row = $t.parent(), i = $row.index(), row = data[i];
var $firstTd = $row.children().eq(0);
if($firstTd.data("haveTable") !== true){
$firstTd.data("haveTable",true);
$firstTd.append('<table class="newTable"><tr><td>NEW TABLE</td></tr></table>');
} else {
$firstTd.data("haveTable",false);
$firstTd.children("table").remove();
}
});
https://jsfiddle.net/e3nk137y/1663/
try
$('#myTable').bootstrapTable().on('click-row.bs.table td', function (e, row, $element)
{
//....my operation
}
Based on my guess, when you click on that cell, you probably want only the triggers for that particular cell to execute and not for the whole table.
This can be achieved by stopping the propagation of event from the table cell to the table row.
$('#myTable').bootstrapTable().on('click-row.bs.table', function (e, row, $element){
//stop the propagation for target cell
if($(event.target).hasClass('myClass')) e.stopPropagation();
//the code for handler
...
...
}
There are many ways stopPropagation can be utilized to do this thing. This was just one of those.
Since I dont know how your other triggers are set, I can't write code that works with those with assumptions.
Try this:
$('#myTable tr td:last-child').on('click', function() {
if( $('.newTable', $(this)).length ) {
$('.newTable', $(this)).remove();
} else {
$(this).append( '<table class="newTable"><tr><td>NEW TABLE</td></tr></table>' );
}
});
I'm wondering if there is a more elegant means of modifying the parameter of an onclick event. I have a table that I am dynamically adding/removing elements from and I re-index the rows. Each row has a delete link that has the row's index (and a duplicate link) that needs to update its parameter to match the modified row id.
Currently my code looks like (simplified)
<a onclick="delRow(1)">delete</a>
and the javascript:
...
html = element.innerHTML;
html = html.replace(/dupRow(\\d+)/g, "dupRow(" + newIndex + ")");
html = html.replace(/delRow(\\d+)/g, "delRow(" + newIndex + ")");
element.innerHTML = html
and I would like it to become something along the lines of
if (element.onclick != null) {
element.onclick.params[0] = newIndex;
}
Any such way of accomplishing this? I also have jQuery if this helps.
Updates:
So thanks to the glorious help of #rich.okelly I have solved my issue
<script>
...
var newRow = '\
<tr>\
<td class="index" col="0">0</td>\
<td>this is content...</td>\
<td>Del</td>\
</tr>';
// re-index table indices in a non-efficient manner
function reIndexTable() {
$("#rpc-builder-table").find('.index').each(function (i) {
$(this).html(i)
})
}
// add row
function addRow() {
for (i = 0; i < $('#addRowCount').attr("value"); i++) {
$("#rpc-builder-table").append(newRow);
}
reIndexTable();
}
$(document).ready(function () {
// add row button
$('#addRowsButton').on('click', function () {
addRow();
});
// delete row
$('#rpc-builder-table').on('click', 'td a[row-delete="true"]', function () {
$(this).closest('tr').remove();
reIndexTable();
});
...
}
</script>
...
<div>
<label>Rows to add: </label>
<input id="addRowCount" value="1" size="2" />
<button id="addRowsButton">Add Row(s)</button>
</div>
<div><table id="rpc-builder-table"><tbody>
<tr>
<th>Idx </th>
<th>Some content (1)</td>
</tr>
</tbody></table></div>
...
I used the .on() function instead of the suggested .delegate() function since it is deprecated. Solution works well - hope it helps someone :)
If you change your html to something similar to:
<tr>
<td>
delete
</td>
</tr>
Then your javascript can be something like:
$('td a[data-delete="true"]').on('click', function() {
$(this).closest('tr').remove();
});
Update
If rows are added dynamically to a pre-exising table (table is interchangeable for any parent element), you can use the delegate method like so:
$('table').delegate('td a[data-delete="true"]', 'click', function() {
$(this).closest('tr').remove();
});
Instead of inline handlers, use event delegation to attach event handlers
$("#tableID").delegate("a", "click", delRow);
$("#tableID").on("click", "a", delRow); //jQuery 1.7
Inside the handler,
var row = $(this).closest("tr").index(); //Get the index of the parent row
Inline handlers get parsed into a function:
function onclick() {
delRow(1);
}
so changing them is difficult. Your example rewrites the entire row with the new parameter, which is bad practice.
The most brain dead solution is getting rid of the parameters and setting a variable isntead.
var row_to_dup = 42;
$("#a_row_dupper").bind('click', function (){
dupItem(row_to_dup);
});
//changing the row to dup
row_to_dup = 17;