Ignore mouseleave events when absolute positioned elements are covering - javascript

I have a table that has a bunch of rows that I need to be both editable and deletable. I've made a <div> which contains a couple of buttons that I want to show up in the relevant position when the rows are hovered. This is all fine. I also want the buttons to disappear when the mouse leaves the table itself. OK, I'll use the mouseleave event, I thought. Unfortunately this is fired when the mouse enters the buttons <div> too, leading to a feedback loop where the buttons constantly show and hide.
This is quite difficult to describe, but hopefully this is illustrative: https://jsfiddle.net/8d726rqt/
I did try to find an answer already, and there are many where the shown and hidden items are children of the parent element, but that's not the case for me, so these solutions don't work. Furthermore, it's often suggested to use pointer-events: none. This does work, but then the buttons don't receive click events, defeating the point.

#edit-control is not inside #top-level-table. Therefore when #edit-control appears and mouse is over it, it triggers the mouseleave event. Then button disappears and mouse enter table again. Thus button appears again. And it becomes a loop, where button keeps showing hiding.
I suggest adding mouseleave event to the wrapper div of #edit-control and #top-level-table.
$(function()
{
$('.list-row').mouseover(function()
{
var offset = $(this).offset();
$('#edit-controls').css({
'top': offset.top + 10,
'left': offset.left + 10
}).fadeIn();
//console.log('fadein');
});
//change to this element with mouseleave event
$('#table-wrapper').mouseleave(function()
{
// console.log('fadeout');
$('#edit-controls').fadeOut();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script crossorigin="anonymous" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="table-responsive" id="table-wrapper">
<table id="top-level-table" class="table table-striped table-bordered">
<thead>
<tr>
<th>Table</th>
</tr>
</thead>
<tbody>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
</tbody>
</table>
<div id="edit-controls" style="display:none; position:absolute; z-index:1" >
<button type="button" class="btn btn-primary">Edit</button>
<button type="button" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</body>
</html>

If buttons block placed some other place, than table you might use this solution:
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script crossorigin="anonymous" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="table-responsive">
<table id="top-level-table" class="table table-striped table-bordered">
<thead>
<tr>
<th>Table</th>
</tr>
</thead>
<tbody>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
<tr class="list-row">
<td>Content<br><br>Things</td>
</tr>
</tbody>
</table>
<div id="edit-controls" style="display:none; position:absolute; z-index:1">
<button id="edit" type="button" class="btn btn-primary">Edit</button>
<button id="delete" type="button" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</body>
$(function()
{
$('.list-row').mouseover(function()
{
var offset = $(this).offset();
$('#edit-controls').css({
'top': offset.top + 10,
'left': offset.left + 10
}).fadeIn();
console.log('fadein');
});
$('#top-level-table').mouseleave(function(event)
{
if (event.relatedTarget.id !== 'edit' &&
event.relatedTarget.id !== 'delete' &&
event.relatedTarget.id !== 'edit-controlls') {
$('#edit-controls').fadeOut();
}
});
});
here is jsfiddle: https://jsfiddle.net/kinos/pbg8dhvr/13/

On the div property:
<div onMouseLeave={(e) => e.preventDefault()}>
....
</div>

Related

how to select $(this) inside a template literal js expression?

I know that every time I call "this" inside the function it will select whatever selector have given it in arguments but how could use template literal like this and get the index of the row generated in the append method ?
$(document).on('click', '.add-row', function () {
$(this).closest("table").find("tbody").append(`
<tr>
<td> ${ $(this).closest("tr").index() } </td>
</tr>
`)
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
</head>
<body>
<table class="table table-bordered">
<thead>
<th>INDEX</th>
<th>SOMETHING</th>
<th><button class="btn btn-primary add-row">ADD ROW</button></th>
</thead>
<tbody></tbody>
</table>
</body>
</html>
You'll need to find the tbody, and see the number of children of that element to get a counter:
$(document).on('click', '.add-row', function () {
var $tbody = $(this).closest("table").find("tbody");
$tbody.append(`
<tr>
<td> ${ $tbody.children().length } </td>
</tr>
`)
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
</head>
<body>
<table class="table table-bordered">
<thead>
<th>INDEX</th>
<th>SOMETHING</th>
<th><button class="btn btn-primary add-row">ADD ROW</button></th>
</thead>
<tbody></tbody>
</table>
</body>
</html>

Why position().top return wrong value in second table?

I have two tables in first table its return position().top fine but when i click on second table then its return same value as in first table, how can i fixed it?
Why both table position().top return same?
$(function() {
$('tr').click(function() {
offsetTop = $(this).position().top;
console.log(offsetTop);
});
});
.myDiv {
overflow-y: auto;
height: 250px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div class="myDiv">
<h2>Table 1</h2>
<table class="table table-bordered">
<tbody>
<tr>
<td>Click here this is first table, its return -1 in console</td>
</tr>
</tbody>
</table>
<h2>Table 2</h2>
<table class="table table-bordered">
<tbody>
<tr>
<td>Click here this is second table, its also return -1 in console why? how can i fix it? how can i get exactly position of this element?</td>
</tr>
</tbody>
</table>
</div>
I assume you trying to get the top relative to the screen top, and not relative to it's parent.
In this case you should use offset() and substruct the window.scrollY
$(function() {
$('tr').click(function() {
offsetTop = $(this).offset().top - window.scrollY;
console.log(offsetTop);
});
});
.myDiv {
overflow-y: auto;
height: 250px;
}
#d {
height: 300px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div id="d"></div>
<div class="myDiv">
<h2>Table 1</h2>
<table class="table table-bordered">
<tbody>
<tr id="2">
<td>Click and see how its top changed with scroll</td>
</tr>
</tbody>
</table>
<h2>Table 2</h2>
<table class="table table-bordered">
<tbody>
<tr>
<td>See how its top changed with scroll</td>
</tr>
</tbody>
</table>
</div>
You can get table position and sum with tr position, in fact, position() return element position depend on own parent position.
$(function() {
$('tr').click(function() {
offsetTop = $(this).position().top;
offsetTopParent = $(this).parents('table').position().top;
//console.log(offsetTop); // return tr offset
//console.log(offsetTopParent); // return table offset
console.log(offsetTop + offsetTopParent);
});
});
.myDiv {
overflow-y: auto;
height: 250px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div class="myDiv">
<h2>Table 1</h2>
<table class="table table-bordered">
<tbody>
<tr>
<td>Click here this is first table, its return -1 in console</td>
</tr>
</tbody>
</table>
<h2>Table 2</h2>
<table class="table table-bordered">
<tbody>
<tr>
<td>Click here this is second table, its also return -1 in console why? how can i fix it? how can i get exactly position of this element?</td>
</tr>
<tr>
<td>Click here this is second table, its also return -1 in console why? how can i fix it? how can i get exactly position of this element?</td>
</tr>
</tbody>
</table>
</div>

Showing more than one DataTable on same page (jQuery)

I am developing a Flask application, I have an HTML template in which I have two tables, for which I want to use the datatable plugin. Here is the code of my HTML template with the tables
<doctype html>
<html>
<head>
<title> car_name </title>
<link rel="stylesheet" type="text/css" href="{{url_for('static', filename='aesthetic.css') }}">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.js"></script>
</head>
<body>
<script>
$(document).ready( function () {
$('#table_1').DataTable();
$('#table_2').DataTable();
} );
</script>
<div class="spacebox"></div>
<div class="boxheader">
<a id="Shops">Shops</a>
</div>
<div id="bigbox">
<table id="table_1" border="1" style="background: white">
<thead>
<tr>
<th><b>Phosphosite ID</b></th>
<th><b>Protein</b></th>
<th ><b>Gene</b></th>
<th><b>Residue</b></th>
</tr>
</thead>
<tbody>
{% for x in searchshops %}
<tr>
<td> {{x.NAME}} </td>
<td> {{x.RESOURCES}} </td>
<td> {{x.CARS}} </td>
<td> {{x.BRANDS}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="spacebox"></div>
<div class="boxheader">
<a id="Cars">Cars</a>
</div>
<div class="bigbox">
<table id="table_2" border="1" style="background: white">
<tr>
<th><b>Name</b></th>
<th ><b>Shop</b></th>
</tr>
{% for x in searchcars %}
<tr>
<td> {{x.CAR}}</td>
<td> {{x.Shop}} </td>
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
(searchshops and searchcars are SQLAlchemy queries to a database, in my Flask python script)
The datatable attributes (search bar, sort columns), show on the first table but not the second one.
I have also tried the following script, (having added class="display" after both tables, based on this example https://datatables.net/examples/basic_init/multiple_tables.html )
<script>
$(document).ready(function() {
$('table.display').DataTable();
} );
</script>
But I have the same problem.
How can I apply the datatable plugin to both tables?
Thank you.
I think it's a bug that it only applies to the first table and not on the succeeding table/s regardless if the first table is initialized or not with DataTable. I've tried it, it's the same.
Maybe you can use this concept. The datatables were rendered serverside.
multitable serverside rendering

How to show a specific icon in a table row?

I have a table and each row has an icon. When you click on the icon, it should show another icon that was hidden. My problem is that when I click on this icon, it always changes the first row, not the row of the icon that I have clicked.
This is my function:
$("#myTable").on('click', 'tbody tr #editAction', function () {
$('#deleteAction').show();
$('#editAction').hide();
});
The attribute id must be unique in a document, you can use class instead. You also have to target the current element with this keyword.
Demo:
$("#myTable").on('click', 'tbody tr .editAction', function () {
$(this).closest('.deleteAction').show();
$(this).hide();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable" style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tbody>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
<td class="deleteAction">delete</td>
<td class="editAction">edit</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
<td class="deleteAction">delete</td>
<td class="editAction">edit</td>
</tr>
</tbody>
</table>
$('#deleteAction') results in a global search in the DOM that returns the first element that matches the id, ensure each id in the DOM is unique.
Try to implement class selector as following
$("#myTable").on('click', 'tbody tr .editAction', function (e) {
$(e.currentTarget).find('.deleteAction').show();
$(e.currentTarget).find('.editAction').hide();
});
As others have mentioned, $('#deleteAction') will return the first element that matches that id. Instead of using IDs, you should use classes. Classes can be used more than once on a page, whereas IDs should not be.
The code below will hide the clicked .editAction, then show the .deleteAction from the same row.
$("#myTable").on('click', 'tbody tr .editAction', function () {
$(this).hide().closest("tr").find(".deleteAction").show();
});
HTML wise, you will need to replace id="#editAction" with class="editAction":
<tr>
<td><img class="editAction"></td>
<td><img class="deleteAction"></td>
</tr>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
</head>
<body>
<table class="table">
<tr>
<td>test1</td>
<td>
<button class="deleteAction">delete</button>
<br>
<button class="editAction">edit</button>
</td>
</tr>
<tr>
<td>test2</td>
<td>
<button class="deleteAction">delete</button>
<br>
<button class="editAction">edit</button>
</td>
</tr>
<tr>
<td>test3</td>
<td>
<button class="deleteAction">delete</button>
<br>
<button class="editAction">edit</button>
</td>
</tr>
</table>
<script type="text/javascript">
$(document).on('click', '.editAction', function () {
var cur = $(this);
cur.parent().find('.editAction').hide();
cur.parent().find('.deleteAction').show();
});
</script>
</body>
</html>

print the value of a variable from javascript to html

How can print the value of variable count in ministries().For example i have 54 object.so it will show ministries(54).How can i print 54(value of count) in ministries.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Data Retrieve</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<style>
#p1 {background-color: violet;}
</style>
</head>
<body>
<div class="container">
<div class="row">
<table id="info_table" class="table">
<tr>
<td><p align="center"><b>Ministry</b></p></td>
</tr>
<tr id="p1">
<td><p align="center"><b>Total ministries()</b></p></td>
</tr>
</table>
</div>
</div>
</body>
</html>
<script>
$.getJSON("http://localhost/directory/ministri.json",function(obj){
var info ='';
//alert(obj.data.length);
var count = obj.data.length;
$.each(obj.data,function(key,value){
info += '<tr>';
info +='<td>'+value.sitename_bn+'<span style="float: right"> > </span>'+ '</td>';
info += '</tr>';
});
$('#info_table').append(info);
});
</script>
It's really simple. Just target your element #p1 and replace its HTML with the value you got.
$('#p1 td').html("<p><b>Total ministries(" + count + ")</b></p>");
Change your table structure to
<table id="info_table" class="table">
<thead>
<tr>
<td><p align="center"><b>Ministry</b></p></td>
</tr>
<tr id="p1">
<td><p align="center"><b>Total ministries()</b></p></td>
</tr>
</thead>
<tbody>
</tbody>
</table>
and then change jQuery code to
$('#info_table > tbody').append(info);

Categories

Resources