My page has a table with two rows, like this:
<table class="table table-condensed">
<tbody>
<tr>
<td class="col-sm-8 room-status" data-roomstatusid="1" data-value="Active" data-edited="false">Active</td>
<td class="col-sm-4"><i class="fas fa-pencil-alt edit-status" style="font-size: 20px;"></i>
<div class="edit-controls hidden"><i class="fas fa-times-circle cancel-status-edit" style="margin-left: 5px;font-size: 20px;"></i><i class="fas fa-save save-status-edit" style="margin-left: 15px;font-size: 20px;"></i>
</div>
</td>
</tr>
<tr id="status-template" class="hidden">
<td class="col-sm-8 room-status" data-roomstatusid="-1" contenteditable="true"></td>
<td class="col-sm-4"><i class="fas fa-pencil-alt edit-status hidden" style="font-size: 20px;"></i>
<div class="edit-controls" data-mode="new"><i class="fas fa-times-circle cancel-status-edit" style="margin-left: 5px;font-size: 20px;"></i><i class="fas fa-save save-status-edit" style="margin-left: 15px;font-size: 20px;"></i>
</div>
</td>
</tr>
</tbody>
</table>
There is a button on the page that adds a row at the start of the table using the html of the hidden #status-template row. All that works fine.
After the new row has been added, I can click the pencil icon on either it or what is now the second row (the one with "Active" in the first cell) and the javascript that detects the click works correctly.
If I click on the first <td> of the inserted row, the javascript that detects that click also works correctly, but if I click the first cell of what is now the second row (which contains "Active", the click is not detected.
My javascript is all delegated to the table element since I know there will be new elements added to the DOM.
The javascript to detect the click on the first <td> of a row looks like this
$('#room-status-table').on('click', 'tbody tr td:first', function() {
if ($(this).hasClass('row-highlight')) {
$(this).removeClass('row-highlight')
} else {
$('#room-status-table tbody tr').each(function() {
$(this)
.find('td:first')
.removeClass('row-highlight')
})
$(this).addClass('row-highlight')
}
})
The javascript to detect the click on the pencil icon is
$('#room-status-table').on('click', '.edit-status', function() {
var cell = $(this).closest('tr').find('.room-status')
$(cell).attr('contenteditable', 'true')
$(cell).focus()
$(this).addClass('hidden')
$(this).next().removeClass('hidden')
$(this).closest('tr').find('td:first').addClass('row-highlight')
})
The code that creates the new row is
$("#new-status").on("click", function() {
var html = "<tr>" + $("#status-template").html() + "</tr>"
$("table > tbody > tr:first").before(html)
$("table > tbody td:first").focus()
$("#edit-room-submit").attr("disabled", "disabled")
})
Grateful for any help in figuring out why the click on the first <td> of the second <tr> is not triggering my click event.
You've misunderstood the delegated selector td:first. What you will want to use is td:first-child.
While :first matches only a single element, the :first-child selector can match more than one i.e. one for each parent. This is equivalent to :nth-child(1).
Replace
.on('click', 'tbody tr td:first', ...)
with
.on('click', 'tbody tr td:first-child', ...)
I just did this at my project. I can share like an example my code which trigger one click and doubleClick at table row added via ajax:
$('table tbody').on('dblclick', 'tr', function(){
if(!$(this).hasClass('tr.selected-row')){
$(this).parent('tbody').find('tr.selected-row, td.selected-row').removeClass('selected-row');
$(this).addClass('selected-row').find('td').addClass('selected-row');
if($(this).find("td a[title='View']").length > 0){
var href = $(this).find("a[title='View']").attr("href");
if(href) {
window.location = href;
}
} else if($(this).find("td a[title='Update']").length > 0){
var href = $(this).find("a[title='Update']").attr("href");
if(href) {
window.location = href;
}
}
}
}).on('click', 'tr', function(){
if(!$(this).hasClass('tr.selected-row')){
$(this).parent('tbody').find('tr.selected-row, td.selected-row').removeClass('selected-row');
$(this).addClass('selected-row').find('td').addClass('selected-row');
}
})
Related
I have the following code which allows me to edit a cell, but the problem is that when I want to click on the link, it forces me to edit instead. I want to be able to edit only when I click on the pen icon, but I can't seem to figure out how to do it.
HTML
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
<table border="1" style="width:100px" style="height:99px" style="margin:0
auto">
<tbody>
<tr>
<td>
<div class="row_data" edit_type="click" col_name="datamapname">
<i class="fa fa-pencil"></i>
<a id="dm" href="https://www.google.com/" target="_blank">Sample</a>
</div>
</td>
</tr>
</tbody>
</table>
Jquery
//--->make div editable > start
$(document).on('click', '.row_data', function(event)
{
//Remove pencil icon.
$(this).find('i.fa-pencil').remove();
//Remove link
$("#dm").removeAttr('href');
event.preventDefault();
if($(this).attr('edit_type') == 'button')
{
return false;
}
//make div editable
$(this).closest('div').attr('contenteditable', 'true');
//add bg css
$(this).addClass('bg-warning').css('padding','5px');
$(this).focus();
$(this).attr('original_entry', $(this).html());
})
//--->make div editable > end
// --> save single field data > start
$(document).on('focusout', '.row_data', function(event)
{
event.preventDefault();
if ($(this).attr('edit_type') == 'button')
{
return false;
}
//Add pencil icon back
$(this).append('<i class="fa fa-pencil"></i>');
//Add link back
$("#dm").attr('href','https://www.google.com/');
})
JSFiddle: https://jsfiddle.net/89zgd1ry/
Wrap the anchor tag in another div and set contentEditable="false".
Try to read this
when I want to click on the link, it forces me to edit instead.
This is because you click handler is on the parent row_data div
I want to be able to edit only when I click on the pen icon
Change
$(document).on('click', '.row_data',
to
$(document).on('click', '.row_data>i.fa-pencil',
this will then refer to the icon so you'll have to make appropriate changes, eg:
$(this).find(".fa-pencil").remove();
becomes
var row = $(this).closest(".row_data");
$(this).remove();
add
$('#dm').click(function( e ){ e.preventDefault(); });
And
$(document).on('click', '.fa-pencil',...
I have a table with rows. In each row there is a "copy to clipboard" button implemented using Clipboard.js
Now I want the table row to be clickable and I want it to redirect to "google.com", if the user clicks anywhere on the row BUT the button.
When the user clicks the button, I want to copy the text to the clipboard, but NOT redirect.
I have tried using the solution suggested in this answer here, but using event.stopPropagation() also disables the Clipboard.js functionality.
Is there an elegant solution for this problem? Here's some code:
<table>
<tr>
<th>Name</th>
<th></th>
</tr>
<tr class='valign-middle' data-href='www.google.com'>
<td>Text</td>
<td>
<button data-clipboard-text='www.facebook.com' id='clipboard-btn'>
<i class="fa fa-clipboard"></i>
</button>
</td>
</tr>
</table>
<script>
// activate Clipboard buttons
var clipboard = new Clipboard('button#clipboard-btn');
// make table rows clickable
$(function(){
$('.table tr[data-href]').each(function(){
$(this).css('cursor','pointer').hover(
function(){
$(this).addClass('active');
},
function(){
$(this).removeClass('active');
}).click( function(event){
document.location = $(this).attr('data-href');
}
);
});
});
</script>
You can have a class for td in tr except for the last one in which your copy button is present, then instead of applying click event on row you can have this click event on each td and then check in click event whether td has that specified class or not, if it has redirect it to google.com else do nothing.
Below is the sample implementation :
<table>
<tr>
<th>Name</th>
<th></th>
</tr>
<tr class='valign-middle' data-href='www.google.com'>
<td class='normalText'>Text</td>
<td>
<button data-clipboard-text='www.facebook.com' id='clipboard-btn'>Copy
<i class="fa fa-clipboard"></i>
</button>
</td>
</tr>
</table>
<script>
var clipboard = new Clipboard('button#clipboard-btn');
// make table rows clickable
(function(){
$('table tr[data-href] td').each(function(){
$(this).css('cursor','pointer').hover(
function(){
$(this).addClass('active');
},
function(){
$(this).removeClass('active');
});
$(this).click( function(event){
if($(this).hasClass("normalText"))
document.location = $(this).parent().attr('data-href');
}
);
});
});
</script>
I can get the id of the data already but the problem how to find that data on html
this is my html
<table cellspacing="0" cellpadding="0" border="0" id="cards" class="table table-striped table-bordered">
<thead>
<tr>
<th>Description</th>
<th>By</th>
<th>Total Votes</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>If the opening scene of this show scared you as a kid, DRINK!</td>
<td>testing testing</td>
<td>1</td>
<td>
<a data-id="1" data-target="#viewCard" data-toggle="modal" class="btn btn-default btn-xs view" href="#"><span class="fa fa-eye"></span> View Card</a>
<a data-id="1" data-target="#editCard" data-toggle="modal" class="btn btn-primary btn-xs edit" href="#"><span class="fa fa-edit"></span> Edit</a>
<a data-id="1" data-target="#deleteCard" data-toggle="modal" class="btn btn-danger btn-xs delete" href="#"><span class="fa fa-remove"></span> Delete</a>
</td>
</tr>
...
</tbody>
</table>
so when the popup out... It will show button and this is the .submitDelete
Delete
and js
$(document).on('click', '.submitDelete', function(e){
e.preventDefault();
var card_id = $(".submitDelete").data('card_id');
var test = $("#cards table tr .delete[data-id='"+card_id+"']"); //<---- idk how to get the tr to be remove... this is what I've tried so far.
console.log(test);
});
EDIT1
I added jsfiddle so you guys know the flow
http://jsfiddle.net/sdxaV/1/
EDIT2
http://jsfiddle.net/sdxaV/12/
Based on the HTML you provided, the .submitDelete element does't have a card_id attribute.
Therefore, change $(".submitDelete").data('card_id') to $(this).attr('data-id') in order to retrieve the correct attribute of the clicked element, rather than the first matching element.
You were also trying to select a table element that is a descendant of a #cards element. The table element has an id of #cards, therefore the selector should be $("table#cards ..."). Or omit table from the selector.
Then to get the closest tr element, chain .closest('tr'):
Working Example
$(document).on('click', '.submitDelete', function(e) {
e.preventDefault();
var card_id = $(this).attr('data-card_id');
var $row = $("table#cards tr .delete[data-id='" + card_id + "']").closest('tr');
$row.remove();
});
I always use jQuery.closest() for this sort of thing. It will navigate up ancestors until it matches.
$(document).on('click', '.submitDelete', function(e){
e.preventDefault();
var test = $(this).closest('tr');
console.log(test);
});
In this circumstance, this is the .submitDelete button that was clicked.
With a Helper Library
The easiest way to do this is instead of making your own method to do this, pull in a library that already wraps the Bootstrap modal like Bootbox. Your example's delete link would be changed to the following:
<a data-id="1" class="btn btn-danger btn-xs delete" href="#"><span class="fa fa-remove"></span> Delete</a>
Your Javascript would be updated to the following:
$(document).on('click', '.delete', function(e){
e.preventDefault();
var $row = $(this).closest('tr');
bootbox.confirm("Are you sure?", function(result) {
$row.remove();
});
});
Notice that we aren't using Bootstrap's HTML attributes to load up the modal anymore. Bootbox is creating the modal for us.
With Vanilla Bootstrap/jQuery
To do this with straight Bootstrap, I would again not use the Bootstrap HTML attributes to directly load up the modal. Something like the following would work. Notice it's not as clean, but this could easily be cleaned up depending on how your JavaScript is setup.
var $row = null;
$(document).on('click', '.delete', function(e){
e.preventDefault();
$row = $(this).closest('tr');
$('#deleteCard').modal();
});
$(document).on('click', '.submitDelete', function(e){
e.preventDefault();
if($row != null) { $row.remove(); $row = null; }
});
One way of cleaning this up would be to put the card id on a data attribute of the modal. It removes the need to store it in a variable somewhere else. Again, cleaning this up requires looking in-depth into what your JavaScript looks like. Good luck.
This is your anchor element <a>:
var test = $("#cards table tr .delete[data-id='"+card_id+"']");
Though it can be shortened. As this will refer to the anchor that was clicked inside the function passed to the on() method. To make it a jQuery object you will need to pass this to $, $( this );.
Now you need to traverse up through the DOM to the table row <tr>. jQuery provides a method called closest() to do this.
var link = $( this );
var tr = link.closest( 'tr' );
// Do what you need to with variable tr.
I have two tables. From the top table you select data items by clicking on a add button which would add that row to the bottom table. In reverse if you select the remove button from the bottom table the row would go back to the top table. Now I am not even sure if it is possible with jQuery to accomplish this without using unique class names...hence me looking for help here.
Here is a Fiddle that is only half working, since I haven't figured out yet if it is possible to do what I am asking.
HTML
<table class="aside-table">
<thead>
<tr>
<th>Data Options
<button type="button" class="btn add-all-selection pull-right" onclick="location.href='#'"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add All Data Options</button></th>
</tr>
</thead>
<tbody>
<tr>
<td>Item 3
<button type="button" class="btn add-selection pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button></td>
</tr>
<tr>
<td>Item 4
<button type="button" class="btn add-selection pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button></td>
</tr>
</tbody>
</table>
<table class="data-selection-table">
<thead>
<tr>
<th>Data Selection Summary
<button type="button" class="btn remove-all-selection pull-right" onclick="location.href='#'"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span> Remove All Data Options</button></th>
</tr>
</thead>
<tr>
<td>Item 1
<button type="button" class="btn pull-right remove-selection"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button></td>
</tr>
<tr>
<td>Item 2
<button type="button" class="btn pull-right remove-selection"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button></td>
</tr>
</table>
jQuery
$(document).ready(function(e) {
$('.add-selection').click(function(){
$(this).closest('tr').find('td').fadeOut("fast");
});
$('.remove-selection').click(function(){
$(this).closest('tr').find('td').fadeOut("fast");
});
});
Here's a full solution that works in both directions and includes changing the classes for the icons.
I added a common class to each table.
HTML Change:
<table class="aside-table items-table">
This single event handler works for both sets of buttons
/* delegate a click handler for both button classes */
$('table.items-table').on('click', '.add-selection, .remove-selection', function(){
/* "this" is the button element instance */
var $btn = $(this).toggleClass('add-selection remove-selection'),
/* define row to be moved by looking up DOM tree*/
$item = $btn.closest('tr'),
/* define other table */
$otherTable = $('.items-table').not( $btn.closest('table'));
/* fade and move to other table */
$item.fadeOut(function(){
/* fade out has finished, can move now */
$otherTable.append($item);
/* switch button icon classes */
$btn.find('span').toggleClass('glyphicon-plus glyphicon-minus')
/* is in new table, can fade in */
$item.fadeIn()
});
});
Note that the clcik event has to be delegated to the table elements since removing an element removes event listeners also
References:
closest() Docs
toggleClass() Docs
DEMO
This is what I did. Updated fiddle here
First I added tbody to the html table element so we can target the data areas.
Then added click events to the table elements instead of buttons so we can use event delegation.
$(document).ready(function() {
$('.aside-table').on('click', '.add-selection', function(){
var $item = $(this).closest('tr');
$item.fadeOut("fast");
var $new = $item.clone();
$new.find('.add-selection').removeClass('add-selection').addClass('remove-selection');
$new.find('.glyphicon').removeClass('glyphicon-plus').addClass('glyphicon-minus');
$('.data-selection-table').find('tbody').append($new);
});
$('.data-selection-table').on('click', '.remove-selection', function(){
var $item = $(this).closest('tr');
$item.fadeOut("fast");
var $new = $item.clone();
$new.find('.remove-selection').removeClass('remove-selection').addClass('add-selection');
$new.find('.glyphicon').removeClass('glyphicon-minus').addClass('glyphicon-plus');
$('.aside-table').find('tbody').append($new);
});
});
If you're not wanting to keep them in order, then basically you can just remove the row, not the cell, and append it to the last row on the other table. You'll need to add another "tbody" tag to the 2nd table so we don't put the rows in the "thead" if there's no rows in the table.
$('.add-selection').on('click', function(){
var $row = $(this)
.closest('tr')
.fadeOut("fast");
$row.detach()
.appendTo($('.aside-table').find('tbody tr:last'))
.find('button')
.removeClass('add-selection')
.addClass('remove-selection')
.find('span')
.removeClass('glyphicon-plus')
.addClass('glyphicon-minus');
});
For the remove function, it'd be the same code w/ the exception of the table class selector, and switch out the classes for the button as well.
I have a table that has 3 columns. In the first column I have a button and I want to check if the second column has a div of not. I am not trying to do this using jQuery.
This is my html
<table class="customFiltersTable" id="customFiltersTable" width="100%" style="background-color: #75A1D0; padding:10px 10px 10px 10px">
<tbody>
</tbody>
</table>
The (dropdown menu) button is generated dynamically inside the 1st column. Here is the script
//create a tr and 3 td inside it then append tr
var fType1 = $('<tr class="rowTableFilters" id="rowFilters'+filtersRow+'" name="rowFilters'+filtersRow+'"><td class="colFilters" id="colFilters'+column1+'" name="colFilters'+column1+'" width="480px" align="center" columnNum="'+column1+'"></td><td class="colFilters" id="colFilters'+column2+'" name="colFilters'+column2+'" width="480px" align="center" columnNum="'+column2+'"></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);
// create the dropdown menu button in the 1st column along with the list (li)
var fType = $('<div class="btn-group" style="padding: 5px; width: 70%;"><button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" style="width: 100%;">Select Filter <span class="caret"></span></button><ul class="dropdown-menu" role="menu" style="width:100%" data-userid="'+(intIdFilters-2)+'" id="filUl'+(intIdFilters-2)+'" currData-value="-1"></ul></div>');
$("#colFilters"+(intIdFilters-2)).append(fType);
$("#filUl"+(intIdFilters-2)).append(li); // li is list already generated.
so the if statement I am using (which not working) is this
$('#customFiltersTable').on('click', '.dropdown-menu li a', function () {
if($(this).closest('td').next('td').find('div').length){
...
}
});
Any idea please?
I believe you could use jQuery's has() method to achieve this:
if($(this).closest('td').next('td').has("div")) {
// It contains a <div> element
} else {
// It doesn't contain a <div> element
}
Edit:
Your code looks good. Try removing the 'td' in the next() function.
var $td = $(this).closest('td').next();
if ($td.find('div').length > 0) { //div exists }