I have a table with an onRowClick handler on the <tr/> element, I want to prevent a click event if I select text inside it, my solution was this:
const getSelectionWithoutClick = (originalHandler: () => void) => {
if (!getSelection()?.toString()) originalHandler();
};
What I found odd is, when I select a text inside a cell, and click on the same cell, the click event is not fired until the selection is cleared, but if click on another cell (even in the same row), while text is selected in the original cell, the click event fires. You know why this happens??
I think you can differentiate between click and select event based on onMouse up
function TablePage() {
function onSelect(e) {
let selection = window.getSelection().toString();
if (selection === '') {
console.log('click');
} else {
console.log('selection', selection);
}
}
return <table>
<thead>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
</thead>
<tbody>
<tr>
<td onMouseUp={onSelect}>Alfreds Futterkiste</td>
<td onMouseUp={onSelect}>Maria Anders</td>
<td onMouseUp={onSelect}>Germany</td>
</tr>
</tbody>
</table>
}
export default TablePage;
Related
Making an food ordering app. There is a first table with all items you can choose. Each item have a button. On this button click it clones the line and put it in a second table containing your chosen items. I would like to change the text content of the button when the element go to the second table. Like "+" in the first table become "-" in the second table (to next delete the item of the second table on "-" click)
HTML
<h1>CHOOSE</h1>
<table id="starters">
<tr>
<th>PRODUCT</th>
<th>PRICE</th>
<th>ADD TO CART</th>
</tr>
<tr>
<td>Cherry</td>
<td>6</td>
<td><button class="item_button">+</button></td>
</tr>
<tr>
<td>Peach</td>
<td>8</td>
<td><button class="item_button">+</button></td>
</tr>
<tr>
<td>Strawberry</td>
<td>12</td>
<td><button class="item_button">+</button></td>
</tr>
</table>
<h1>YOUR CHOICE</h1>
<table id="products_cart">
</table>
JS
let basket = document.getElementById("products_cart")
let buttons = document.querySelectorAll('.item_button');
for (button of buttons) {
button.addEventListener('click', cloneLine);
}
function cloneLine(e) {
let td = e.target.parentNode;
let tr = td.parentNode;
let clone = tr.cloneNode(true);
basket.appendChild(clone);
}
I tried different things like to get (querySelectorAll) the buttons and change their innerHTML (or textContent or innerText) with no success. I also tried to create another button and to replace the former by the newer.
When you click on a table row it adds a class that changes it's appearance to reflect it's selected.
$('#my_table tbody').on( 'click', 'tr', function () {
$(this).toggleClass('selected');
} );
However, I also have some buttons in a column that let you do things specific to the row:
Item Amount Action
--------------------------------
Apple 10 [Buy] [Delete]
Banana 5 [Buy] [Delete]
Orange 14 [Buy] [Delete]
When I click one of the individual buttons, it also triggers the table row '.selected' class to be added, but I don't want this to occur when clicking buttons.
You can use Event​.stop​Propagation() on button click:
$('#my_table tbody').on( 'click', 'tr', function () {
$(this).toggleClass('selected');
} );
$('#my_table tbody').on( 'click', 'button', function (e) {
e.stopPropagation();
});
.selected{
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="my_table">
<thead>
<th>Item</th>
<th>Amount</th>
<th>Action</th>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td>10</td>
<td><button>[Buy]</button><button>[Delete]</button></td>
</tr>
<tr>
<td>Banana</td>
<td>5</td>
<td><button>[Buy]</button><button>[Delete]</button></td>
</tr>
<tr>
<td>Orange</td>
<td>14</td>
<td><button>[Buy]</button><button>[Delete]</button></td>
</tr>
</tbody>
</table>
You can use stopPropagation() or preventDefault() on buttons onclick event. This will prevent event bubling to parent elements of button (td, tr, table and so on). Assuming your buttons class as 'row-button' following is a sample code:
$('.row-button').on('click', function(event)){
event.stopPropagation();
//Do what are intended upon button click.
}
You might make sure that the td being clicked on is not in the column with the buttons. With :not, you can ensure that the matched element doesn't match a particular selector, and with :nth-child, you can specify the 3rd td in its container as the one to be excluded:
$('#my_table tbody').on('click', 'tr td:not(:nth-child(3))', function() {
console.log('click registered');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="my_table">
<tr>
<td>td 1</td>
<td>td 2</td>
<td><button>button</button></td>
</tr>
</table>
You are experiencing a feature of the DOM called Event Propagation.
What you want to do is prevent this from occurring by calling Event.stopPropagation() in the handlers for your <td> clicks
To stop propagation with a jQuery event handler, simply return false on the last line of your td click handlers.
Let's say I have a button in a table which adds a new row to a table:
<td><a onclick="addRow()"></a></td></tr>...
and I want to reference $(this) or $(this).closest('tr') from the function at the bottom of the page.
function addRow(){
$(this) // contains all information from the row which pressed the button
}
Simply passing a javascript variable from the HTML will result in null (as expected). Is there a way to reference the row that pressed the button?
The RECOMMENDED way of doing this is unobtrusive and delegated - give the link a class:
var $tb = $("#someTable");
$tb.on("click", ".addRow", function(e) { // delegation to allow new rows' links to work
e.preventDefault(); // stop any click side effects
var $row = $(this).closest("tr");
$tb.append($row.clone())
});
a { text-decoration:none }
td,th { padding:3px }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>Add</th>
</tr>
</thead>
<tbody id="someTable">
<tr>
<td>1st</td>
<td>2nd</td>
<td><a class="addRow" href="#">+</a></td>
</tr>
<tr>
<td>3rd</td>
<td>4th</td>
<td><a class="addRow" href="#">+</a></td>
</tr>
</tbody>
</table>
Use this
<td><a onclick="addRow(this)"></a></td></tr>
and then:
function addRow(e){
console.log($(e)) // contains all information from the row which pressed the button
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a onclick="addRow(this)">Clickme</a>
You can reference the row that you clicked using an event.
<td>Add</td>
and in javascript you can check the event
<script>
function addRow(event) {
console.log(event);
}
</script>
this is a simple demonstration of what i have, this is a table with a single row in it,
<table id="test_table">
<tr>
<td>name</td>
<td>age</td>
<td>action</td>
</tr>
<tr>
<td>test name</td>
<td>20</td>
<td class="delete">delete</td>
</tr>
</table>
and if i click on the delete td this row would be hidden
$('.delete').click(function(){
$(this).parent().parent().hide();
});
and i have a simple form of name and age, when i click on the add button it appends it to the table
$('#test_input').click(function(){
var name = $('#name').val();
var age = $('#age').val();
$('#text_table').append('<tr><td>'+name+'</td><td>'+age+'</td><td class="delete">delete</td></tr>');
});
the problem is i if i click on the new appended row it would hide like its not even there, what ever i try to do using the appended row, it wouldn't take it, is there something wrong that im doing ?
$('#test_table') should be $('#test-table').
And you should bind the on-click on the added row.
Another solution is to create a delegated event.
$('body').on('click', '.delete', function() {
$(this).parent().parent().hide();
});
I have a html table with rows.
Each row has a action column with a button and when pressing this button i want to show a input field in the second td which the user have to fill out and submit, first then the event/click is completed else the input should disappear again.
<table>
<thead>
<tr>
<th>ID</th>
<th>user-Input</th>
<th>data3</th>
<th>data4</th>
<th>data5</th>
<th>Action</th>
</tr>
</thead>
<tbody id="customers">
<tr>
<td>1</td><td></td><td>data</td><td>data</td><td>data</td><td><button type='button' class='acceptCustomerBut'>GO</button></td>
</tr>
</tbody>
</table>
javascript/jquery
$(document).on("click", ".acceptCustomerBut", function(e) {
e.preventDefault();
$(this).parent().parent().find("td:nth-child(2)").html("<input type='number' name='customer_id'>");
// DO SOMETHING
});
DO SOMETHING - im thinking if its possible to make the function detect if the input has received values with jquery's .on("change") if not, hide the input field?
Try this,
$(document).on("click", ".acceptCustomerBut", function(e) {
e.preventDefault();
var $td=$(this).closest('tr').find("td:eq(1)");
if($td.find('input').length){ // check input length, if exists then hide it
$td.find('input').hide();
} else { // else add it
$td.html("<input type='number' name='customer_id'>");
}
});
Live Demo