Mimic <a> behavior on hover and on click with javascript - javascript

I have a table and each row should link to a page.
I want to keep the structure of the html as is (not a bunch of divs and a grid like Wrapping HTML table rows in <a> tags)
Everything works with the javascript, but I am missing the bottom left tooltip that shows the url on hover from an tag. I also want the option to open in a new tab with CMD (mac) or CTRL (windows/linux).
I am currently doing the solution with jQuery:
$('.clickable-row').on('click', function () {
const url = $(this).attr('data-url')
if (typeof url === 'string') {
window.location.href = url
}
});
My html (twig):
<table class='table'>
<thead>
<tr>
{% for h in data.header %}
<th>{{h|trans}}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in data.rows %}
{% set url = data.getOnClickURL(loop.index - 1) %}
<tr {% if url %} class='clickable-row' data-url="{{url}}" {% endif %}>
{% for r in row %}
<td>{{r|trans}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

try this solution without writing Javascript code using only HTML and CSS.
table {
width: 100%;
border-collapse: collapse;
}
table tr {
position: relative;
}
table tr td {
border: 1px solid black;
text-align: center;
}
table tr a {
position: absolute;
width: 100%;
display: block;
height: 100%;
top: 0px;
left: 0px;
}
<table>
<tr>
<td> 1 </td>
<td>2 </td>
<td>3 </td>
</tr>
<tr>
<td>1 </td>
<td>2 </td>
<td>3 </td>
</tr>
<tr>
<td>1 </td>
<td>2 </td>
<td>3 </td>
</tr>
<tr>
<td>1 </td>
<td>2 </td>
<td>3 </td>
</tr>
<tr>
<td>1 </td>
<td>2 </td>
<td>3 </td>
</tr>
</table>

Related

Show/hide a table row based on nested class

I have a button on a page that I want to only show rows that have a certain class (target-class in my example) within them. If you press the button again, then all rows are shown.
I'm not sure how to check if target-class is within <tr class="show-hide-this-one">
<button id="btn-toggle_target" type="button">Show Targets Only</button>
<table>
<tbody>
{% for item in first_list %}
<tr class="show-hide-this-one">
<td> {{ item.title }} </td>
<td>
<table><tbody>
{% for subitem in item.sublist %}
<tr>
<td>
{{ subitem.value }}
{% if value == 0 %}
<span class="target-class"> Looking for this one </span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody></table>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<script type="text/javascript">
function toggleTarget() {
$btnToggle = $("#btn-toggle_target")
var showTargetOnly = $btnToggle.hasClass("target-only")
if (showTargetOnly) {
$btnToggle.html("Show Targets Only").removeClass("target-only");
$().show();
}
else {
$btnToggle.html("Show All Records").addClass("target-only");
$().hide();
}
}
(function () {
$("#btn-toggle_target").on('click', function() {
toggleTarget();
});
}());
</script>
it was not so easy because you dont have class or id but with a little loop its ok:
$("#btn-toggle_target").on('click', function() {
toggleTarget();
});
function toggleTarget() {
var showTargetOnly = $("#btn-toggle_target").hasClass("target-only");
if (showTargetOnly) {
$("#btn-toggle_target").html("Show Targets Only").removeClass("target-only");
$(".show-hide-this-one table tr").show();
}
else {
$("#btn-toggle_target").html("Show All Records").addClass("target-only");
$(".show-hide-this-one table td").each(function(){
if($(this).find(".target-class").length == 0) $(this).closest("tr").hide();
})
//this loop coul be replaced by
//$(".show-hide-this-one table td:not(:has(.target-class))").closest("tr").hide();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-toggle_target" type="button">Show Targets Only</button>
<table>
<tbody>
<tr class="show-hide-this-one">
<td> Item 1 </td>
<td>
<table><tbody>
<tr>
<td>
0
<span class="target-class"> Looking for this one </span>
</td>
</tr>
<tr>
<td>
1
</td>
</tr>
<tr>
<td>
3
</td>
</tr>
</tbody></table>
</td>
</tr>
<tr class="show-hide-this-one">
<td> Item 2 </td>
<td>
<table><tbody>
<tr>
<td>
4
</td>
</tr>
</tbody></table>
</td>
</tr>
</tbody>
</table>
i think, you could replace this loop :
$(".show-hide-this-one table td").each(function(){
if($(this).find(".target-class").length == 0) $(this).closest("tr").hide();
})
by
$(".show-hide-this-one table td:not(:has(.target-class))").closest("tr").hide();

Regular expression to match string between { and } in javascript?

Given the following string, I tried to use regular expression match any string between just { and }, and surround it with <tr style="display:none;"><td></td></tr>.
I tried write the following script but it does not work.
$(document).ready(function() {
table = ` <table border="1">
{% Acount Summary 2018 %}
<tbody>
{I}
<tr style="height: 25px;">
<td style="padding-left: 10px;">Account Number: </td>
{# II #}
<td>Account</td>
{% Active Account %}
</tr>
{ Requested Account #}
<tr style="height: 25px">
<td style="padding-left: 10px;">Number of Requests: </td>
<td>Request</td>
{{ III }}
</tr>
{#
<tr style="height: 25px">
<td style="padding-left: 10px;">Customer: </td>
<td>Contract Customer</td>
</tr>
#}
<tr style="height: 25px">
<td style="padding-left: 10px;"> Customoer ID</td>
<td>ID</td>
</tr>
{# CustomerName #}
</tbody>
{# Account #}
{{ Inactive }}
</table>
`;
table.replace(/({\s*?.*?.*})/g, '<tr style="display:none;"><td>$1</td></tr>');
console.log(table);
$('#COA').html(table);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="COA"></div>
What was missing? How could I correct script above to achieve above result? Thanks.
You need to reassign your variable table:
table = table.replace( ... )
I edited your RegEx for it to be simpler and exclude the {} : {([^}]*)}
Note that your method won't handle the nested {}. You would have to go the recursive road for it to do so.
$(document).ready(function() {
table = ` <table border="1">
{% Acount Summary 2018 %}
<tbody>
{I}
<tr style="height: 25px;">
<td style="padding-left: 10px;">Account Number: </td>
{# II #}
<td>Account</td>
{% Active Account %}
</tr>
{ Requested Account #}
<tr style="height: 25px">
<td style="padding-left: 10px;">Number of Requests: </td>
<td>Request</td>
{{ III }}
</tr>
{#
<tr style="height: 25px">
<td style="padding-left: 10px;">Customer: </td>
<td>Contract Customer</td>
</tr>
#}
<tr style="height: 25px">
<td style="padding-left: 10px;"> Customoer ID</td>
<td>ID</td>
</tr>
{# CustomerName #}
</tbody>
{# Account #}
{{ Inactive }}
</table>
`;
table = table.replace(/{([^}]*)}/g, '<tr style="display:none;"><td>$1</td></tr>');
console.log(table);
$('#COA').html(table);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="COA"></div>

JavaScript - On click on undefined number of elements to toggle multiple elements

I have a table that needs to have an undefined number of rows that should display a set number of elements when clicked (in this case div, because I read that it's the best way to use toggle on tr). Best I could do is make it for an already set number of elements...
jsfiddle.net - This is with the set number of elements.Working code..
And this is all I got so far trying to figure it out.
Working js code:
$('.warning').on('click', function(e) {
var $ele = $(this).nextUntil('.warning').find('td > div');
$ele.slideToggle();
});
});
In this case, I need each clicked table row to display three corresponding divs.
Obviously, answer with jQuery but I would appreciate a solution in vanilla js as well.
EDIT: I am sorry, I neglected to mention I want to add a sliding animation. And slideToggle doesn't seem to work...
EDIT2: Marked best answer by Terry.
Changed fiddle to working code.
We can actually greatly simplify your markup for your table rows:
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
...and use the following logic:
.nextUntil('.warning') to select the trailing <tr> after each .warning element. See the documentation for .nextUntil().
Use .slideToggle() to show/hide elements, without the need to use overly verbose CSS detection
Here is the logic above, written in jQuery:
$('.warning').on('click', function() {
// Selects all siblings until the next `.warning` <tr>
var $ele = $(this).nextUntil('.warning').find('td > div');
$ele.slideToggle();
});
If you only want to target downstream <tr> that has the class hidden (useful in the scenario where there might be other irrelevant <tr>s in the way that you do not want to toggle), you might want to add an optional filter instead:
$('.warning').on('click', function() {
// Selects all siblings until:
// 1. the next `.warning` <tr>, and
// 2. has the class "hidden"
var $ele = $(this).nextUntil('.warning').filter(function() {
return $(this).hasClass('hidden');
}).find('td > div');
$ele.slideToggle();
});
Of course this means that you get strange stacked borders when hiding elements, because you are technically hiding the table row content, but not collapsing the table rows/cells themselves.
Here is a proof-of-concept example:
$(function() {
$('.warning').on('click', function() {
var $ele = $(this).nextUntil('.warning').filter(function() {
return $(this).hasClass('hidden');
}).find('td > div');
$ele.slideToggle();
});
});
table {
width: 75%;
border-collapse: collapse;
}
tr,
td {
border: 2px solid #AEAEAE;
padding: 0;
}
td {
width: 50px;
}
.hidden td div {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mytable">
<tbody>
<tr class="warning">
<td>Click to show</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="warning">
<td>Click to show</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="warning">
<td>Click to show</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
<tr class="hidden">
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
<td>
<div>Hidden.</div>
</td>
</tr>
</tbody>
</table>
Please see below snippet , note that I've set all the hidden class , class='hidden' , it's usless to name each of them differntly :
$(".warning").on("click",function(){
$(this).nextUntil(".warning").find(".hidden").slideToggle();
})
table {
width: 75%;
border-collapse: collapse;
}
tr, td {
border: 2px solid #AEAEAE;
padding: 0;
}
td {
width: 50px;
}
.hidden, .hidden1, .hidden2 {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mytable">
<tbody>
<tr class="warning">
<td>Click to show</td> <td>Name</td> <td>Age</td>
</tr>
<tr class="active">
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
</tr>
<tr class="active">
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
</tr>
<tr class="warning">
<td>Click to show</td> <td>Name</td> <td>Age</td>
</tr>
<tr class="active">
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
</tr>
<tr class="warning">
<td>Click to show</td> <td>Name</td> <td>Age</td>
</tr>
<tr class="active">
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
<td>
<div class="hidden">Hidden.</div>
</td>
</tr>
</tbody>
</table>
$(".warning").on("click", function() { use jQuery .on will add the event to dynamic element (future generated element).
then find the next hidden and toggle will do the trick.
check the example:
$(".warning").on("click", function() {
var nextHidden = $(this).next('.hidden');
nextHidden.find('div').slideToggle();
});
table {
width: 75%;
border-collapse: collapse;
}
tr,
td {
border: 2px solid #AEAEAE;
padding: 0;
}
td {
width: 50px;
}
.hidden div {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mytable">
<tbody>
<tr class="warning">
<td>Click to show</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr class="active hidden">
<td>
<div class="">Hidden.</div>
</td>
<td>
<div class="">Hidden.</div>
</td>
<td>
<div class="">Hidden.</div>
</td>
</tr>
<tr class="warning">
<td>Click to show</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr class="active hidden">
<td>
<div class="">Hidden.</div>
</td>
<td>
<div class="">Hidden.</div>
</td>
<td>
<div class="">Hidden.</div>
</td>
</tr>
<tr class="warning">
<td>Click to show</td>
<td>Name</td>
<td>Age</td>
</tr>
<tr class="active hidden">
<td>
<div class="">Hidden.</div>
</td>
<td>
<div class="">Hidden.</div>
</td>
<td>
<div class="">Hidden.</div>
</td>
</tr>
</tbody>
</table>

jQuery expand/collapse a link

I am working with a MVC view that has a 3 columns table. The table displays a list of Products. Column #1 (product name) contains links to a product specific page. When a user clicks on the links, I want to expand and display the product description and at the end of the product description, I want to include a link that takes the user to the product page. If a user clicks on the link again, I want to collapse it back. I have a model that represents the product and the product description is stored in its own field.
The table is built and populated as below. Any insight on how to achieve the expand/collapse via jQuery is very much appreciated.
<table id="products">
<thead>
<tr>
<th>Product Name</th>
<th>Type</th>
<th>Price</th>
</tr>
</thead>
<tbody>
foreach (product p in model.products)
{
<tr>
<td>
#p.name
</td>
<td>
#p.type
</td>
<td>
#p.price
</td>
</tr>
}
</tbody>
</table>
The easiest way to to utilize product IDs as well. Add the specific product ID as a data attribute, then using jQuery, pull that attribute and reuse it to target rows containing the descriptions.
$('.productname').on('click', function() {
var id= $(this).attr('data-id');
$(this).toggleClass('active');
$('.data' + id).slideToggle(500);
});
.hide {display: none; }
/* -- below is just to "pretty up" the snippet ------ */
table {
width: 100%;
background: #eee;
border-collapse: collapse;
border: 1px solid #aaa;}
th { background: #cef; color: #4cf; text-transform: uppercase; font-size: 0.8em; padding: 3px;border: 1px solid #aaa;}
td { font-size: 1.1em; padding: 5px 10px; border: 1px solid #aaa; border-bottom: none; }
tr.collapsed td { padding: 0; border: none; }
.productname:hover, .active { background: #eff; }
.productdesc { padding: 5px 10px; background: #eff; border-top: 1px solid #aaa; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="products">
<thead>
<tr>
<th>Product Name</th>
<th>Type</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<!--
foreach (product p in model.products)
{
-->
<tr class="productname" data-id="prodID00">
<!-- Change data-id="prodID00" to data-id="#p.productI‌D" -->
<td>
#p.name
</td>
<td>
#p.type
</td>
<td>
#p.price
</td>
</tr>
<tr class="collapsed">
<td colspan="3">
<div class="hide productdesc dataprodID00">
<!-- Change class="hide productdesc dataprodID00" to class="hide productdesc data#p.productI‌D" -->
<p>#p.productDescription #p.productLink</p></div>
</td>
</tr>
<!-- } -->
<!-- below are just manual iterations of the row above -->
<tr class="productname" data-id="prodID01">
<td>
#p.name
</td>
<td>
#p.type
</td>
<td>
#p.price
</td>
</tr>
<tr class="collapsed">
<td colspan="3">
<div class="hide productdesc dataprodID01">
<p>product description and link</p></div>
</td>
</tr>
<tr class="productname" data-id="prodID02">
<td>
#p.name
</td>
<td>
#p.type
</td>
<td>
#p.price
</td>
</tr>
<tr class="collapsed">
<td colspan="3">
<div class="hide productdesc dataprodID02">
<p>product description and link</p></div>
</td>
</tr>
<tr class="productname" data-id="prodID03">
<td>
#p.name
</td>
<td>
#p.type
</td>
<td>
#p.price
</td>
</tr>
<tr class="collapsed">
<td colspan="3">
<div class="hide productdesc dataprodID03">
<p>product description and link</p></div>
</td>
</tr>
<tr class="productname" data-id="prodID04">
<td>
#p.name
</td>
<td>
#p.type
</td>
<td>
#p.price
</td>
</tr>
<tr class="collapsed">
<td colspan="3">
<div class="hide productdesc dataprodID04">
<p>product description and link</p></div>
</td>
</tr>
</tbody>
</table>
Note where the prodID is located in the rows.....
I removed the foreach function and brackets because it's invalid HTML. But if they are there and dynamically generate the HTML it'll work fine. The rows I used are just manual iterations opposed to dynamic iterations.

How can I change the background color of a td when a link in the td is clicked?

I have tried searching, but I am stuck.
Basically I am making a jeopardy game board; which I created using a table. I would like to change the background-color of the td after it has been clicked on. The challenge I am facing is that (1) I am using a link to direct to the question/answer (yes, I know this could be done other ways, but I need to learn more to advance and I am working on that); (2) After searching for answers, I can't seem to get it to work with the code I have.
Here is my [JSFiddle]https://jsfiddle.net/hLyauL5a/)
Html:
<table>
<thead>
<tr>
<th>Stuff</th>
<th>Stuff </th>
<th>Stuff</th>
<th>Stuff</th>
<th>Stuff</th>
</tr>
</thead>
<tbody>
<tr>
<td>100</td>
<td>100</td>
<td>100</td>
<td>100</td>
<td>100</td>
</tr>
<tr>
<td>200</td>
<td>200</td>
<td>200</td>
<td>200</td>
<td>200</td>
</tr>
<tr>
<td>300</td>
<td>300</td>
<td>300</td>
<td>300</td>
<td>300</td>
</tr>
<tr>
<td>400</td>
<td>400</td>
<td>400</td>
<td>400</td>
<td>400</td>
</tr>
<tr>
<td>500</td>
<td>500</td>
<td>500</td>
<td>500</td>
<td>500</td>
</tr>
</tbody>
</table>
CSS:
jQuery code:
$("table tr td").click(function() {
$(this).css("background", "#626975");
});
I would appreciate any help!
I see two problems. One, you have not included jquery or your javascript file in your html. Your jsfiddle does not have jquery loaded.
Two, assuming the above was just a problem getting your question across on Stack Overflow, you haven't waited for the document to load before attaching event listeners. The selector tries to select something that isn't there yet, and nothing is attached. What you need is:
$(document).on('ready', function(){
$("table tr td").click(function(e) {
$(this).css("background", "#626975");
});
});
Working example:
$(()=> {
$("table tr td").click(function() {
$(this).css("background", "#626975");
});
});
body {
cursor: pointer;
}
/*gameboard*/
table {
width: 100%;
border-collapse: collapse;
}
tr {
background: #1f293a;
color: #47ba04;
}
th {
background: #1f293a;
color: white;
font-weight: bold;
min-width: 200px;
}
td {
color: #47ba04;
background: #1f293a;
min-width: 100px;
height: 130px;
}
td,
th {
padding: 6px;
border: 1px solid #ccc;
text-align: center;
}
a {
color: #47ba04;
text-decoration: none;
}
/* For the question pages*/
#question,
#answers {
width: 100%;
height: 800px;
border: 1px solid black;
background-color: #1f293a;
color: white;
font-weight: bold;
}
div.question h2,
div.answers h2 {
margin: 0;
position: absolute;
top: 40%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Stuff</th>
<th>Stuff</th>
<th>Stuff</th>
<th>Stuff</th>
<th>Stuff</th>
</tr>
</thead>
<tbody>
<tr>
<td>100
</td>
<td>100
</td>
<td>100
</td>
<td>100
</td>
<td>100
</td>
</tr>
<tr>
<td>200
</td>
<td>200
</td>
<td>200
</td>
<td>200
</td>
<td>200
</td>
</tr>
<tr>
<td>300
</td>
<td>300
</td>
<td>300
</td>
<td>300
</td>
<td>300
</td>
</tr>
<tr>
<td>400
</td>
<td>400
</td>
<td>400
</td>
<td>400
</td>
<td>400
</td>
</tr>
<tr>
<td>500
</td>
<td>500
</td>
<td>500
</td>
<td>500
</td>
<td>500
</td>
</tr>
</tbody>
</table>
You could launch the links in a new window by adding target="_blank" attribute to your anchor tags:
<td>100</td>
$('a').click(function(e){
e.preventDefault();
$(this).parent().css('background-color','blue');
});
So,using JQuery, if you click on an tag, don't jump on whatever link it is, you prevent the default event, then you get its parent which is the element and you add the css style as shown. Here is the html that I used as an example:
<table>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td >Table</td>
<td bgcolor="#00FF00">$100</td>
</tr>
Generally, a hyperlinks like <a herf="" onclick="">contain two events: onclick and herf. The order of execution --- 'onclick' in front of 'herf'. so making onclick method return 'false' if you want to page can't jump on whatever link it is when you click hyperlink. Code is as follows.
$(function(){
$("a").on("click",function(){
$(this).css("background", "#626975");
return false;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Stuff</th>
<th>Stuff</th>
<th>Stuff</th>
</tr>
</thead>
<tbody>
<tr>
<td>100</td>
<td>100</td>
<td>100</td>
</tr>
</tbody>
</table>

Categories

Resources