elements within a hidden element are not hidden - javascript

In trying to build a page where I can filter the types of jobs and the offices using the hide/show function, I find that if an element is hidden, then an element underneath the element is "told" to hide, it doesn't actually hide. In other words, hide only works if the actual element is shown.
Here is the code, to duplicate, Hide office 2, then hide developers, then show office 2 again. The developers (which "should" be hidden) display within office 2.
Is there a way around this? It would seem jquery would hide the "sub" elements as well, but it doesn't.
<input type="checkbox" id=office1 name="test" class="link1" />Office 1<BR>
<input type="checkbox" name="office2" checked='true' class="link2"/>Office 2<BR>
<input type="checkbox" name="office3" checked='true' class="link3" />Office 3<BR>
<input type="checkbox" name="developer" checked='true' class="link4" />Developer<BR>
<input type="checkbox" name="receptionist" checked='true' class="link5" />Receptionist<BR>
<input type="checkbox" name="manager" checked='true' class="link6" />Manager<BR>
<table border='1'>
<tr>
<td class="toggle-item-link1"><B>Office 1</B><HR>
<div class="toggle-item-link6"><BR>Manager</div>
<div class="toggle-item-link6"><BR>Manager</div>
<div class="toggle-item-link6"><BR>Manager</div>
</td>
</tr>
<tr >
<td class="toggle-item-link2"><B>Office 2</B><HR>
<div class="toggle-item-link4"><BR>Developer</div>
<div class="toggle-item-link4"><BR>Developer</div>
<div class="toggle-item-link6"><BR>Developer</div>
<div class="toggle-item-link5"><BR>Receptionist</div>
</td>
</tr>
<tr>
<td class="toggle-item-link3"><B>Office 3</B><HR>
<div class="toggle-item-link4"><BR>Developer</div>
<div class="toggle-item-link4"><BR>Developer</div>
<div class="toggle-item-link5"><BR>Receptionist</div>
</td>
</tr>
<td>
</td>
</tr>
</table>
<script>
$(document).ready(function() {
$('[class^=link]').click(function() {
if ($(this).attr("checked")) {
var $this = $(this);
var x = $this.attr("className");
//when 'checked'
$('.toggle-item-' + x).show(1000);
return;
}
//when 'unchecked'
var $this = $(this);
var x = $this.attr("className");
$('.toggle-item-' + x).hide(1000);
});
});
</script>

Since .hide() with an animation speed will only run on visible elements, you can add a case in there for hidden ones as well, like this (a few more optimizations here, just cutting down on code):
$('[class^=link]').click(function() {
var x = $(this).attr("className");
if (this.checked) {
$('.toggle-item-' + x).show(1000);
} else {
$('.toggle-item-' + x).hide(1000).filter(':hidden').hide();
}
});
You can try out a demo here. We're just accounting for the already :hidden elements that won't animate and skipping to them doing a display: none; by calling .hide() without an animation speed.

In addition to the hide()/show(), use a class named hidden, with the CSS:
.hidden {
display: none;
}
When you hide the item, you also add the class hidden. And when you show it, you also remove hidden.

Here's a cleaner and simpler solution:
$("#randomdiv").hide(1000, function() { $(this).css("display", "none"); });
The callback of hide/show in jQuery does fire even if the function itself didn't do its thing due to the parent elements. Using the above method with jQuery, the elements will hide regardless if they are in a hidden parent element or not, while also performing the usual smooth transition if they are shown.

Related

HTML show/hide parts of a table onclick of table headers

I have a nested HTML table. I would like to show parts of the nested table depending on the header clicked using javascript
http://jsfiddle.net/TtWTR/103/
so far it shows all three parts. I want to click header A and show only optionA, click headerB and only show optionB etc etc. Not sure if ive set it up right as all three are showing. thanks
To achieve expected result, use below option oh hide() and show() methods
$('.trigger').click(function() {
console.log($(this).text())
var selectedHdr = $(this).text();
$('.nested tr').hide();
$('.nested tr#'+selectedHdr).show();
});
https://codepen.io/nagasai/pen/vdabJQ
Usually I find it convenient to use CSS class selectors on the "root" element (in your case that would be .toptable) allowing you to toggle it to show and hide child elements.
<table class="toptable">
<tr class="accordion">
<td class="A trigger">A</td>
<td class="B trigger">B</td>
<td class="C trigger">C</td>
</tr>
<tr>
<td>
<table>
<tr class="content A">
<!-- will toggle using show-A -->
</tr>
</table
</td>
</tr>
</table>
Then you can make sure to hide the .content rows using CSS unless specific classes are set on the top table:
.content {
display: none; /* content hidden by default */
}
.show-A .A.content {
display: table; /* show when the parent table has .show-A set */
}
Now you just have to add event listeners to your triggers to toggle the classes for the different content rows:
const toptable = document.querySelector('.toptable');
['A', 'B', 'C'].forEach((group) => {
const trigger = document.querySelector(`.${group}.trigger`);
trigger.addEventListener('click', () => {
toptable.classList.toggle(`show-${group}`);
});
});
This can be done using the following script
$('.nested').hide();
$('tr .trigger').click(function() {
var target_id= "#"+$(this).attr('id')+"-table";
$('.nested').not(target_id).hide();
$(target_id).show();
});
and is shown in http://jsfiddle.net/TtWTR/152/

Hide/Blank out a div until checkbox is selected

I am trying to finalise design of a product page and basket template for my new site but am having trouble putting all the pieces together.
In the html code below the cart/basket is called using <div class="ct-cart"></div> but I need this to either not be visible or blanked out in some way so that a customer has to have ticked the checkbox to agree with the terms and conditions before they can interact with the cart/basket.
I've tried a few scripts I've found online to try and hide it but have been unable to get it to work, even after (hopefully) removing any jQuery conflicts.
Any help would be greatly appreciated.
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart"></div>
Pure JS implementation. (in case you dont really need jquery)
document.getElementById('tandc').onchange = function(){
var cart = document.getElementsByClassName('ct-cart')[0];
if (this.checked) cart.classList.remove('hide');
else cart.classList.add('hide');
}
.hide{
display: none;
}
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart hide">Shown only if checked :)</div>
Something like this:
(Change event on checkbox triggers visibility class on cart div)
$('#tandc').on('change', function(){
if ($(this)[0].checked) {
$('.ct-cart').addClass('ct-cart-visible');
} else {
$('.ct-cart-visible').removeClass('ct-cart-visible');
}
})
/* I would use special classes for showing/hiding, just to give more flexibility on styling, how the cart appears */
.ct-cart {
display: none;
}
.ct-cart-visible {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true"
class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart">CART CONTENTS</div>
When the checkbox changes you need to run a function.
if the checkbox is :checked, show() the .ct-cart. Otherwise hide the cart.
$('#tandc').change(function(){
if($(this).is(":checked")){
$(".ct-cart").show();
}else{
$(".ct-cart").hide();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart" style="display:none;">
Cart
</div>
One further approach:
function toggle() {
// convert the NodeList returned by document.querySelectorAll()
// into an Array, using Array.from():
Array.from(
// using document.querySelectorAll() to find the elements that
// match the selector returned from changed-element's
// custom data-toggle attribute:
document.querySelectorAll(this.dataset.toggle)
// iterating over the Array of nodes:
).forEach(
// using an Arrow function - which avoids changing the
// 'this' - to toggle the class of 'hidden' depending
// on whether the changed-checbox is currently checked
// or not (applying the class-name if the evaluation is
// true, removing it if false):
el => el.classList.toggle('hidden', !this.checked)
);
}
// creating a custom Event (albeit in this case it's the
// browser's 'change' event):
let changeEvent = new Event('change'),
// caching a reference to the relevant element upon which
// the function should fire:
check = document.getElementById('tandc');
// binding the toggle() function (note the deliberate lack of
// parentheses) as the event-handler for the 'change' event:
check.addEventListener('change', toggle);
// firing the 'change' event on page load,
// in order that the relevant element will be
// shown or hidden appropriately:
check.dispatchEvent(changeEvent);
function toggle() {
Array.from(
document.querySelectorAll(this.dataset.toggle)
).forEach(
el => el.classList.toggle('hidden', !this.checked)
);
}
let changeEvent = new Event('change'),
check = document.getElementById('tandc');
check.addEventListener('change', toggle);
check.dispatchEvent(changeEvent);
.ct-cart {
opacity: 1;
transition: opacity 0.5s linear;
}
.hidden {
opacity: 0.1;
}
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control" data-toggle=".ct-cart" /><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart">Cart content</div>
References:
JavaScript:
Array.prototype.forEach().
Array.from().
Arrow functions.
Element.classList API.
Element.datalist.

Traversing on each span under table > tr > td > div

How to traverse on each span under table > tr > td > div ?
I would like to hide those span elements once click on the anchor tag that beneath the same tr level.
JSFiddle
$(document).ready(function() {
$(".hide").click(function(){
$('#table td div span').each(function(){
var $span = $(this);
$(this).siblings().hide();
var spanattr = $span.attr('class');
alert(spanattr);
});
});
});
HTML:
<table id="table">
<tbody>
<tr>
<td class="tdspan">
<div class="container">
<span class="spanelem">First</span>
</div>
</td>
<td class="tdspan">
<div class="container">
<span class="spanelem">Second</span>
</div>
</td>
<td class="tdspan">
<div class="container">
<span class="spanelem">3rd</span>
</div>
</td>
<td>
Hide
</td>
</tr>
</tbody>
<br>
</table>
<span id="text"></span>
I already searched for other questions and used the provided solution such as below link but I'm not able to figure it out.
jquery to traverse the div and get its span details
You don't need for loops there.
Simply .find() span with class .spanelem in a closest <tr> parent of the clicked element:
$(".hide").click(function(){
$(this).closest('tr').find('.spanelem').hide();
// Or using selector context (.find() equivalent but a bit shorter)
// $('.spanelem', $(this).closest('tr')).hide();
});
JSFiddle JSFiddle
References:
.closest()
.find()
selector context
Are you just trying to hide the spans themselves? You are hiding their siblings, and since they are the only children of their parent div, there is nothing else to hide. If you want to hide the spans themselves, then just change
$(this).siblings().hide();
to
$(this).hide();
If you have multiple rows, then you can just crawl up the tree from the .hide button that was clicked to its ancestor row, then find all the spans within that row. You may want to search on a particular class, or all spans, but I don't know for sure how you identify which elements you want to hide.
Something like
$(this).closest('tr').find('span').each(function() {
Updated JSFiddle here: https://jsfiddle.net/fk9jgrLx/4/
If your table structure is as in provided example, and if you will have multiple rows:
$(document).ready(function() {
$(".hide").click(function(){
$(this).parent().siblings().find('span').hide();
});
});
https://jsfiddle.net/L1j9psz6/1/ - remove all spans from row...

onmouseout not triggering but onmouseover is

Here is a simplified fiddle
I have a table with sub-groupings inside of it. I want these sub-groupings to be hidden until the user clicks the sub-header row, which looks like this:
<tr class="title" name="titleGroup"
onmouseover='this.innerHTML=this.innerHTML.replace("---","+++");'
onmouseout='this.innerHTML=this.innerHTML.replace("+++","---");'
onclick="$('.Group').toggle();">
<td colspan="2">--- Group ---</td>
</tr>
So, onmouseover, should change the row to look like: +++ Group +++
and onmouseout should change it back to: --- Group ---
However, only the onmouseover triggers and I cannot get the text to go back.
I initially had the mouse over/out calling a function, but that has the same result. Also note that this page is dynamically generated so the text is not always "Group".
What am I doing wrong and how can I get onmouseout to reset the text?
Maybe you wanted to use onmouseleave event? :)
The proper use of replace function in your case and onmouseleave event:
<table width="550px">
<tr class="title" name="titleGroup" >
<td
onmouseover='this.innerHTML=this.innerHTML.replace(/-{3}/g,"+");'
onmouseleave='this.innerHTML=this.innerHTML.replace(/\+{3}/g,"-");'
onclick="$('.Group').toggle();"
colspan="2">--- Group ---</td>
</tr>
<tr class="Group" style="display:none;">
<td>
<b>Group</b>
HCS:</td>
<td>
<input type="checkbox" name="did4" />
</td>
</tr>
<tr class="Group" style="display:none;">
<td>
<b>Group</b>
NCD:</td>
<td>
<input type="checkbox" checked="" name="did5" />
</td>
</tr>
</table>
ANOTHER EDIT:
Firefox doesn't support onmouseleave event on TR marks! Move those events deffinition to
<td>
Building off of adeneo's fiddle, using jQuery with mouseleave is the way to go. However, the text could include a - or + so I had to update a bit to specifically look for 3 in a row.
Here is the final jQuery:
$('.title').on('mouseenter mouseleave', function(e) {
$('td', this).text(function(_,txt) {
return txt.replace(/[+]{3}|[-]{3}/g, function(x) {
return x=='---' ? '+++' : '---';
});
});
});
http://jsfiddle.net/jQRR7/29/
Checkout http://jsfiddle.net/jQRR7/30/
This works (at least in webkit browsers, Firefox still to be done)
onmouseover='this.innerHTML=this.innerHTML.replace(/-/g,"+");'
onmouseleave='this.innerHTML=this.innerHTML.replace(/\+/g,"-");'
It contains 2 issues:
a) replace() will replace only 1x, unless you hand over a regular expression (attention: do not surround the regex by quotes!) More about replace() can be found at http://devdocs.io/javascript/global_objects/string/replace DevDocs.io JS replace()
b) mouse over seems to be called, but mouseout just 1x,so only 1 time +++ will be replaced
Can you switch to CSS3 (pseudo elements like :after are supported by all major browser version) or do you need to stick on js?
take a look at http://jsfiddle.net/jQRR7/31/
HTML
<table>
<tr class="title" name="titleGroup" style="background: #c3c3c3" onclick="$('.Group').toggle();">
<td colspan="2">Group with CSS3</td>
</tr>
</table>
CSS
.title td {
font-weight: bold;
text-align: center;
cursor: pointer;
}
td:before{
content: '+++ ';
}
td:after{
content: ' +++';
}
tr:hover td:before{
content: '--- ';
}
tr:hover td:after{
content: ' ---';
}

Using mouseover and mouseout in a element makes a hover blinking continuously

I am rendering two elements on a JSP page dynamically, with dynamic IDs. On mouse over of each element I am rendering a div, and on mouse out I am making the same display value none. The issue is when I hover on the div, the div is keeping on blinking. How can I solve this?
Example code:
<table>
<tr>
<td>
<div onmouseover="showblock(hoverdivid)" onmouseout="hideblock(hoverdivid)">india</div>
<div class="hoverdiv" id="dynamicallygenerated">
<li>a list of checkboxes with state names of the country hovered will be inserted using ajax</li>
</div>
</td>
<td>
<div onmouseover="" onmouseout="">america</div>
<div class="hoverdiv" id="dynamicallygenerated">
<li>a list of checkboxes with state names of the country hovered will be inserted using ajax</li>
</div>
</td>
</tr>
</table>
<script>
var showblock;
var hideblock;
$(document).ready(function (e) {
showblock = function (id) {
$("#" + id).show();
}
hideblock = function (id) {
$("#" + id).hide();
}
});
</script>
Extending my question
i mentioned that am inserting checkboxes in the hover using ajax, in the same hover i have an add button which adds the values that i checked in the hover to some other div outside the table. i have two countries so two hovers with their cites so when i checked and click on add the values of two hovers to be displayed which are checked should display individually suggest me the approach to follow to solve the above requirement
This is happening because when the hoverdiv is shown your mouse is on it thus the mouseleave event is triggered so the hoverdiv disappears and then your mouse is on the first div again so the mouseenter event is triggered so hoverdiv appears again.... and so on.. this causes the flickering
My best suggestion will be to nest the hoverdiv: (You'll have to tweak the css a bit)
<table>
<tr>
<td>
<div onmouseover="" onmouseout="">
india
<div class="hoverdiv"></div>
</div>
</td>
<td>
<div onmouseover="" onmouseout="">
america
<div class="hoverdiv"></div>
</div>
</td>
</tr>
</table>
When the hoverdiv is inside the other div, mouseleave will not be triggered when you hover the hoverdiv
Working Demo http://jsfiddle.net/cse_tushar/FKacT/1
HTML
<table border="1">
<tr>
<td>
<div class="div">india</div>
<div class="hoverdiv" id="dynamicallygenerated">
<li>a list of checkboxes with state names of the country hovered will be inserted using ajax</li>
</div>
</td>
<td>
<div class="div">america</div>
<div class="hoverdiv" id="dynamicallygenerated">
<li>a list of checkboxes with state names of the country hovered will be inserted using ajax</li>
</div>
</td>
</tr>
</table>
css
td{
vertical-align: top;
}
js
$(document).ready(function () {
$('.div').hover(function () {
x = $(this).css('width');
$(this).parent().find('.hoverdiv').show();
$(this).css('width', $(this).parent('td').width());
}, function () {
$(this).css('width', x);
$(this).parent().find('.hoverdiv').hide();
});
});

Categories

Resources