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;
Related
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();
});
Pretty much what the title says; I am trying to add icons to shipping selections in Woocommerce, since sometimes the form is filled in on page load. I've created this
$(document).ready( function () {
$('.shipping_method').each( function () {
$this = $(this).closest('td');
if ( this.value = 'table_rate_shipping_freship' ) $this.addClass('shipups');
});
});
This doesn't work, and I'm not sure why.
An additional point is that the shipping method value can change based on information entered further up the form. So would having something like the following be okay?
$(document).ready( function () {
$('.shipping_method').each( function () {
$this = $(this).closest('td');
if ( this.value = 'table_rate_shipping_freship' ) $this.addClass('shipups');
});
});
$(document).ready( function () {
$('.shipping_method').change(function() {
$this = $(this).closest('td');
if ( this.value = 'table_rate_shipping_freship' ) $this.addClass('shipups');
});
});
I'm guessing not since it's basically doing what's been done before but adding a .change() to it. Any help would be really appreciated.
Thanks.
Edit: By request, the HTML from the Woocommerce checkout relating to shipping method:
<tr class="shipping">
<th>Shipping and Handling</th>
<td>
UPS Next Working Day (Free) <input type="hidden" name="shipping_method[0]" data-index="0" id="shipping_method_0" value="table_rate_shipping_freship" class="shipping_method">
</td>
</tr>
$("input[value='table_rate_shipping_freship']").parent().addClass('shipups');
try this. it will add class to parent td
posted answer working fine,
But if you need something general, here you go :)
function addCustomClass(target, className, valueToCheck) {
$("input[value='" + valueToCheck + "']").closest(target).addClass(className);
}
Usage:
addCustomClass('td', 'shipups', 'table_rate_shipping_freship');
I am trying to add and delete rows (by Id) to my table dynamically. The add button works fine but I am not sure why the delete button doesn't work (it's either deletes the last row or doesn't work). Any suggestion please?
Here is my table:
<table class="customFiltersTable" id="customFiltersTable">
<tbody>
</tbody>
</table>
The Javascript add button has this code inside:
filtersRow = filtersRow + 1;
var fType1 = $('<tr class="rowTableFilters" id="rowFilters'+filtersRow+'" name="rowFilters'+filtersRow+'"><td class="colFilters" id="colFilters'+column1+'" name="colFilters'+column1+'" width="480px" align="center"></td><td class="colFilters" id="colFilters'+column2+'" name="colFilters'+column2+'" width="480px" align="center"></td><td class="delButton" id="delButton" name="delButton" width="40px" align="center"><button type="button" class="btn btn-link" id="deleteFilter'+filtersRow+'" name="deleteFilter'+filtersRow+'" style="float: right;">Del</button></td></tr>');
$("#customFiltersTable").append(fType1).promise().done(function () {
$("#deleteFilter" + filtersRow).click(function(){
var row = document.getElementById("rowFilters"+filtersRow);
row.parentNode.removeChild(row);
});
});
Thanks!
Acquaint yourself with jQuery's event delegation, https://learn.jquery.com/events/event-delegation/. You'll learn that you can avoid attaching the delete click listener to every row you add, and instead attach that listener once to the table element:
$('#customFiltersTable').on('click', 'button', function () {
$(this).closest('tr').remove();
});
You're incrementing filtersRow; however your click function only gets evaluated at the time you press the button. In other words, this code:
function(){
var row = document.getElementById("rowFilters"+filtersRow);
row.parentNode.removeChild(row);
}
is executed on click and will run with whatever value of filtersRow you last incremented. You'll always be removing the last row.
Perhaps something like:
function () {
$(this).closest('tr').remove();
}
Sorry, this is compiled in my head.
To add row:
var tmp = '<tr id="4_r"><td>row4</td></tr>';
$('#myTable tbody').append(tmp);
To delete row have id="4_r":
var iddel = "4_r";
$('#myTable').closest('table').find('tbody > tr')
.each(function(){
var idr = this.id;
if(idr == iddel){
$(this).remove();
}
});
OVERVIEW:
When I click a button i want to
insert a new row at the end of a table
copy the cells and contents from the first row of the table
give unique ids to the elements within the cells
assign a focus event listener to all inputs in the page.
PROBLEM:
The event handlers are not firing on the correct elements in IE8. For example if I focus on the last input in the table, the first input gets highlighted.
CLARIFICATION:
This works in IE10, Chrome.
Does not work in IE8 which is my target browser.
I know of ways
to get around this.My aim is NOT to find a workaround but to
understand what my mistake is, in the given code.
The example code is just a quick simplified version of the problem. I am not asking for code optimization thats not relevant to the question.
Change event does not work too.
CODE:
HTML:
<table width="200" border="1" id="myTable">
<tr>
<td>
<input type='text' id='row0col0' name='row0col0'>
</td>
</tr>
</table>
<button id="addRow">Add Row</button>
JS:
function addFocusListener() {
$("input").unbind();
$("input").each(function () {
var $this = $(this);
$this.focus(function () {
var newThis = $(this);
newThis.css('background-color', 'red');
});
});
}
function addRowWithIncrementedIDs() {
var table = document.getElementById("myTable");
var newRow = table.insertRow(-1);
var row = table.rows[0];
var rowNum = newRow.rowIndex;
for (var d = 0; d < row.cells.length; d++) {
var oldCell = row.cells[d];
newCell = oldCell.cloneNode(true);
newRow.appendChild(newCell);
for (var c = 0; c < newCell.childNodes.length; c++) {
var currElement = newCell.childNodes[c];
var id = "row" + rowNum + "col" + d;
$(currElement).attr('name', id);
$(currElement).attr('id', id);
}
}
}
$(document).ready(function () {
$("#addRow").click(function () {
addRowWithIncrementedIDs();
addFocusListener();
});
});
OTHER APPROACHES THAT WORK:
changing from jQuery binding to regular JS binding. I.e from
$this.focus(function () {....});
to
this.onfocus =function () {....};
Attaching the event handler as they are rendered.
FIDDLE:
http://jsfiddle.net/sajjansarkar/GJvvu/
RELATED LINKS IN SO:
jQuery event listener doesn't work in IE 7/8
EDIT
Sorry, I just noticed your comment that you want to understand the error in your code.
I can quickly tell you one error, and that is mixing jQuery and native DOM methods. If you have dedicated yourself to using a very powerful library, then use all of it's features, not just the ones you understand.
The below code uses event delegation (to fix your focusing problem) and jQuery methods to more simply add a row to the table than with native methods.
If you're going to use jQuery, then you might as well use it all the way:
var t = $('#myTable');
$(document)
.on('focus','#myTable input',function() {
$(this).css('background','red')
})
.on('click','#addRow',function() {
//create a new row
var
newIndex,
r = t.find('tr').eq(0).clone();
//append it to the table
r.appendTo(t);
//update newIndex - use it for later
newIndex = r.index();
//update the name/id of each of the inputs in the new row
r.find('input').each(function() {
var
el = $(this),
id = 'row'+newIndex+'col'+el.closest('td').index();
el.attr('id',id).attr('name',name);
});
});
http://jsfiddle.net/GJvvu/1/
You don't need to loop through your inputs and bind a focus handler to each of them, jQuery automatically collects all DOM elements that match the selector and performs it's focus API function on each of them:
Change this:
function addFocusListener() {
$("input").unbind();
$("input").each(function () {
var $this = $(this);
$this.focus(function () {
var newThis = $(this);
newThis.css('background-color', 'red');
});
});
}
To this
function addFocusListener() {
$('input')
.unbind()
.focus(function(){
$(this).css('background-color','red');
});
}
$("#addRow").live("click", function(){
addRowWithIncrementedIDs();
addFocusListener();
});
Try out above code... this should work..
I have the following HTML in a JSP file:
<div class="custList">
<table class="dataGrid">
<c:forEach var="cust" items="${custList}">
<tr>
<td>${cust.number}</td>
<td>${cust.description}</td>
<td>${cust.type}</td>
<td>${cust.status}</td>
</tr>
</c:forEach>
</table>
</div>
I need to be able to trigger a 'click' event on each of the dynamically created <tr> tags and also be able to access the values of the <td> tags (of the clicked <tr>) from within the JavaScript function. I have this function already, but sadly it doesn't seem to be working.
$(document).ready(function() {
$("div.custList > table > tr").live('click', function() {
alert("You clicked my <tr>!");
//get <td> element values here!!??
});
});
Update (Jan 2016): jQuery.live is deprecated (as noted here:http://api.jquery.com/live/)
As of jQuery 1.7, the .live() method is deprecated. Use .on() to
attach event handlers.
Unless otherwise definied (<tfoot>, <thead>), browsers put <tr> implicitly in a <tbody>.
You need to put a > tbody in between > table and > tr:
$("div.custList > table > tbody > tr")
Alternatively, you can also be less strict in selecting the rows (the > denotes the immediate child):
$("div.custList table tr")
That said, you can get the immediate <td> children there by $(this).children('td').
Try jQuery's delegate() function, like so:
$(document).ready(function(){
$("div.custList table").delegate('tr', 'click', function() {
alert("You clicked my <tr>!");
//get <td> element values here!!??
});
});
A delegate works in the same way as live() except that live() cannot be applied to chained items, whereas delegate() allows you to specify an element within an element to act on.
This work for me!
$(document).ready(function() {
$(document).on("click", "#tableId tbody tr", function() {
//some think
});
});
Since TR elements wrap the TD elements, what you're actually clicking is the TD (it then bubbles up to the TR) so you can simplify your selector. Getting the values is easier this way too, the clicked TD is this, the TR that wraps it is this.parent
Change your javascript code to the following:
$(document).ready(function() {
$(".dataGrid td").click(function() {
alert("You clicked my <td>!" + $(this).html() +
"My TR is:" + $(this).parent("tr").html());
//get <td> element values here!!??
});
});
$("body").on("click", "#tableid tr", function () {
debugger
alert($(this).text());
});
$("body").on("click", "#tableid td", function () {
debugger
alert($(this).text());
});
$(this).find('td') will give you an array of td's in the tr.
<script>
jQuery(document).ready(function() {
jQuery("tr").click(function(){
alert("Click! "+ jQuery(this).find('td').html());
});
});
</script>