jQuery Change image depending on the link data-key in each parent - html

I have a section 2 blocks: one - with 3 images, second - with 3 links. Each image has it's own class (class=".img1") that is connected to a definite link with datakey=".img1".
When I hover over each link the definite image is being shown.
The section is a repeater block, that has a loop of images inside (I use ACF for this).
So when I have multiple sections on the page, the link hover from one section changes images in all other sections.
I was trying to use .each() to specify the parent section and then call .hover for links, but it doesn't work the way I need. I'm stuck in this and seems need to use another option.
JSfiddle with 1 section - https://jsfiddle.net/vernigoranataly/Lnwmjq3c/42/
JSfiddle with 2 sections - https://jsfiddle.net/vernigoranataly/kLtz5v4c/4/
JS:
$('.section_product-category ').each(function() {
$('.prodcat_btn .button-link').hover(
function() {
$($(this).data("key")).addClass('active');
$($('.prodcat_btn .button-link').not(this).data('key')).removeClass('active');
},
function() {
$($(this).data("key")).removeClass('active');
$($('.prodcat-img1')).addClass('active');
}
);
});
HTML:
<section class="section_product-category ">
<div class="prodcat_imgs">
<div class="prodcat_img prodcat-img1 active">
<img width="720" height="970" src="https://i.postimg.cc/k4pHm2DW/CTA-image.png" class="attachment-full size-full">
</div>
<div class="prodcat_img prodcat-img2">
<img width="345" height="480" src="https://i.postimg.cc/GhwC8fhG/visit-us-wine-glass.jpg" class="attachment-full size-full">
</div>
<div class="prodcat_img prodcat-img3">
<img width="1035" height="1440" src="https://i.postimg.cc/3NLm6GRH/social-image-three.jpg" class="attachment-full size-full">
</div>
</div>
<div class="prodcat_text">
<h2>Category #1 links</h2>
<div class="prodcat_btn btn">
<a class="button-link" data-key=".prodcat-img1" href="https://google.com">Link text here</a><br>
<a class="button-link" data-key=".prodcat-img2" href="https://google.ca">One more link btn</a><br>
<a class="button-link" data-key=".prodcat-img3" href="https://google.ua">Link text #3</a><br>
</div>
</div>
</section>

Update
I misunderstood what one part of your code was trying to do, and had replaced it with a different approach. I've updated my answer to use that part of your original code.
The problem is because each set has a <div> with the same class, like prodcat-img1, and the code which makes an image active:
$($(this).data("key")).addClass('active');
which evaluates to, eg:
$('.prodcat-img1').addClass('active');
matches all <div>s with that class, ie every one on the page.
The solution is to target only the ones in the current <section>, using something like:
$(this)
.closest('.section_product-category')
.find($(this).data("key"))
.addClass('active');
$(this) is the current element which triggered the hover/unhover event;
.closest() will traverse up the DOM tree until it finds the first match. In this case we look for the parent <section> which encloses this set of links and images;
.find() searches down the DOM tree from the current element for elements matching the selector. In this case we look for the (single!) element inside the <section> we found with a class matching your data-key;
Next, The same problem exists with this line:
$($('.prodcat_btn .button-link').not(this).data('key')).removeClass('active');
It will target every div on the page with the relevant class (eg .prodcat-img1), not just the one in the current section.
We can use the same fix though - start at the parent <section>, find the divs with active class, and remove that class. We just wrap the whole selector in the same code as above:
$(this)
.closest('.section_product-category')
.find($($('.prodcat_btn .button-link').not(this).data('key')))
.removeClass('active');
There is one other issue with this line - if you remove the class from the <div>s after you add it to the one we want, you're left with none of them with the class! :-) You need to remove the class from everything first, then add it to just the one we want. You already have that the right way around in the hover-out handler, just not in this hover handler.
Another issue is this code:
$('.section_product-category ').each(function() {
$('.prodcat_btn .button-link').hover( ...
Here you are iterating over all .section_product-category on the page, and adding handlers for $('.prodcat_btn .button-link'). But $('.prodcat_btn .button-link') matches every one of those elements on the page. So on the first iteration, you add a handler which matches every $('.prodcat_btn .button-link') on the page. The second iteration, you do it all again! The handlers just add up, they don't overwrite each other, and this means that every time you mouse over one of your links, your handler code runs 2x, or 3x if you have 3 sets, etc. You can confirm this by putting a console.log() inside your hover function - you'll see as many log lines written as you have <section>s, for a single mouse-over.
If you're lucky they won't interfere with each other, but depending on what they do they can, and you end up with weird behaviour. You can just remove the iteration - the single selector matches everything.
Here's a working snippet, starting from your 2-section JSFiddle, with those issues fixed:
$('.prodcat_btn .button-link').hover(
function() {
// $($(this).data("key")).addClass('active');
// $($('.prodcat_btn .button-link').not(this).data('key')).removeClass('active');
let $section = $(this).closest('.section_product-category');
// My original approach to remove active classes in this section
// $section.find('.prodcat_img').not($(this)).removeClass('active');
// Your original approach, updated to only target the current section
$section.find($($('.prodcat_btn .button-link').not($(this)).data('key'))).removeClass('active');
$section.find($(this).data("key")).addClass('active');
},
function() {
// $($(this).data("key")).removeClass('active');
// $($('.prodcat-img1')).addClass('active');
let $section = $(this).closest('.section_product-category');
$section.find($(this).data("key")).removeClass('active');
$section.find('.prodcat-img1').addClass('active');
}
);
.section_product-category {
display: flex;
width: 90%;
margin-bottom: 20px;
}
.section_product-category>div {
width: 70%;
}
.section_product-category>div:first-child {
width: 30%;
}
h2 {
margin-bottom: 45px;
}
.prodcat_img {
display: none;
overflow: hidden;
position: relative;
padding-top: 135%;
border: 1px solid blue;
}
.prodcat_text {
padding: 20px 20px 20px 40px;
}
.prodcat_img img {
position: absolute;
top: 0;
height: 100%;
width: 100%;
object-fit: cover;
}
.prodcat_img.active {
display: block;
}
.button-link {
margin-bottom: 7px;
display:block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="section_product-category ">
<div class="prodcat_imgs">
<div class="prodcat_img prodcat-img1 active">
<img width="720" height="970" src="https://i.postimg.cc/k4pHm2DW/CTA-image.png" class="attachment-full size-full">
</div>
<div class="prodcat_img prodcat-img2">
<img width="345" height="480" src="https://i.postimg.cc/GhwC8fhG/visit-us-wine-glass.jpg" class="attachment-full size-full">
</div>
<div class="prodcat_img prodcat-img3">
<img width="1035" height="1440" src="https://i.postimg.cc/3NLm6GRH/social-image-three.jpg" class="attachment-full size-full">
</div>
</div>
<div class="prodcat_text">
<h2>Category #1 links</h2>
<div class="prodcat_btn btn">
<a class="button-link" data-key=".prodcat-img1" href="https://google.com">Link text here</a><br>
<a class="button-link" data-key=".prodcat-img2" href="https://google.ca">One more link btn</a><br>
<a class="button-link" data-key=".prodcat-img3" href="https://google.ua">Link text #3</a><br>
</div>
</div>
</section>
<section class="section_product-category ">
<div class="prodcat_imgs">
<div class="prodcat_img prodcat-img1 active">
<img width="720" height="970" src="https://i.postimg.cc/k4pHm2DW/CTA-image.png" class="attachment-full size-full">
</div>
<div class="prodcat_img prodcat-img2">
<img width="345" height="480" src="https://i.postimg.cc/GhwC8fhG/visit-us-wine-glass.jpg" class="attachment-full size-full">
</div>
<div class="prodcat_img prodcat-img3">
<img width="1035" height="1440" src="https://i.postimg.cc/3NLm6GRH/social-image-three.jpg" class="attachment-full size-full">
</div>
</div>
<div class="prodcat_text">
<h2>Category #2 links</h2>
<div class="prodcat_btn btn">
<a class="button-link" data-key=".prodcat-img1" href="https://google.com">Link text here</a><br>
<a class="button-link" data-key=".prodcat-img2" href="https://google.ca">One more link btn</a><br>
<a class="button-link" data-key=".prodcat-img3" href="https://google.ua">Link text #3</a><br>
</div>
</div>
</section>

Related

Use CSS to hide adjacent DIV based on content

Here are two potential situations in my HTML:
<div class="ptb_sold">
<span class="ptb_one_line">Sold</span>
</div>
<div class="ptb_link_button">
<a class="ptb_link_button" target="_blank" href="https://test.html">Click to Register</a>
</div>
<div class="ptb_sold"></div>
<div class="ptb_link_button">
<a class="ptb_link_button" target="_blank" href="https://test.html">Click to Register</a>
</div>
My goal is to hide "ptb_link_button" in the first one, but allow the "ptb_link_button" div to display in the second example. Basically, if the item is sold, I do not want to display the "Register" button.
I initially thought this would work:
div.ptb_sold:empty+.ptb_link_button {
display: none;
}
<div class="ptb_sold">
<span class="ptb_one_line">Sold</span>
</div>
<div class="ptb_link_button">
<a class="ptb_link_button" target="_blank" href="https://test.html">Click to Register - Link one</a>
</div>
<div class="ptb_sold"></div>
<div class="ptb_link_button">
<a class="ptb_link_button" target="_blank" href="https://test.html">Click to Register - Link two</a>
</div>
But unfortunately it does not. Any other suggestions?
If I understood you correctly, then I think this would be the approach:
// Hides the button if sold
div.ptb_sold + .ptb_link_button a.ptb_link_button {
display: none;
}
// Show the button if not sold
div.ptb_sold:empty + .ptb_link_button a.ptb_link_button {
display: block;
}
Example - https://jsfiddle.net/4o1gvnjx/
Also, I would consider changing the class name of the container for the button to be something like 'ptb_link_button-container' to avoid confusion. That way, the CSS selector would be more streamlined.

Why does toggling an anchor's child element with display cause a double tap, while toggling with opacity does not?

Why does toggling display and opacity on an anchor's child elements affect touch events differently on iOS devices?
I have a navigation menu in which each item contains an image and a short string of text.
Each image has a :hover state that uses the same shared overlay image.
If the :hover pseudo class sets the overlay image's display value, users on iOS devices have to tap the link twice.
If the :hover pseudo class sets the overlay image's opacity value, users on iOS devices do not have to tap the link twice.
In both cases, it doesn't matter if the overlay image covers the entire base image or is a smaller inset overlay.
In both cases, including the :active and :focus pseudo classes does not change the behavior.
I know that I can just remove the :hover rules with JavaScript for touch devices. I'm wondering if anyone knows the why there is a difference between display and opacity.
a {
display: inline-block;
height: 200px;
position: relative;
width: 150px;
}
a img.overlay {
display: block;
left: 0;
position: absolute;
top: 0;
}
a.overlay-display img.overlay {
display: none;
}
a.overlay-display:hover img.overlay {
display: block;
}
a.overlay-opacity img.overlay {
opacity: 0;
}
a.overlay-opacity:hover img.overlay {
opacity: 1;
}
<p>
Set overlay display:
</p>
<a class="overlay-display overlay-display-first" href="http://www.google.com" target="_blank">
<img class="overlay" src="http://placehold.it/150x150/ff0000">
<img src="http://placehold.it/150x150"> link text
</a>
<a class="overlay-display overlay-display-last" href="http://www.google.com" target="_blank">
<img src="http://placehold.it/150x150">
<img class="overlay" src="http://placehold.it/150x150/ff0000"> link text
</a>
<a class="overlay-display overlay-display-first" href="http://www.google.com" target="_blank">
<img class="overlay" src="http://placehold.it/50x50/ff0000">
<img src="http://placehold.it/150x150"> link text
</a>
<a class="overlay-display overlay-display-last" href="http://www.google.com" target="_blank">
<img src="http://placehold.it/150x150">
<img class="overlay" src="http://placehold.it/50x50/ff0000"> link text
</a>
<p>
Set overlay opacity:
</p>
<a class="overlay-opacity overlay-opacity-first" href="http://www.google.com" target="_blank">
<img class="overlay" src="http://placehold.it/150x150/ff0000">
<img src="http://placehold.it/150x150"> link text
</a>
<a class="overlay-opacity overlay-opacity-last" href="http://www.google.com" target="_blank">
<img src="http://placehold.it/150x150">
<img class="overlay" src="http://placehold.it/150x150/ff0000"> link text
</a>
<a class="overlay-opacity overlay-opacity-first" href="http://www.google.com" target="_blank">
<img class="overlay" src="http://placehold.it/50x50/ff0000">
<img src="http://placehold.it/150x150"> link text
</a>
<a class="overlay-opacity overlay-opacity-last" href="http://www.google.com" target="_blank">
<img src="http://placehold.it/150x150">
<img class="overlay" src="http://placehold.it/50x50/ff0000"> link text
</a>
Additionally, it doesn't seem to matter if I'm toggling an inline element or a block element. In this snippet, I'm toggling a span inside the anchor.
a {
display: inline-block;
height: 200px;
position: relative;
width: 150px;
}
a.text-display span.overlay {
display: none;
}
a.text-display:hover span.overlay {
display: inline;
}
a.text-opacity span.overlay {
opacity: 0;
}
a.text-opacity:hover span.overlay {
opacity: 1;
}
<p>
Set text display:
</p>
<a class="text-display text-display-last" href="http://www.google.com" target="_blank">
<img src="http://placehold.it/150x150"> link text
<span class="overlay">some other text</span>
</a>
<p>
Set text opacity:
</p>
<a class="text-opacity text-opacity-last" href="http://www.google.com" target="_blank">
<img src="http://placehold.it/150x150"> link text
<span class="overlay">some other text</span>
</a>
According to the iOS Developer Library documentation for One-Finger Events:
Mouse events are delivered in the same order you'd expect in other web
browsers illustrated in Figure 6-4. If the user taps a nonclickable
element, no events are generated. If the user taps a clickable
element, events arrive in this order: mouseover, mousemove, mousedown,
mouseup, and click. The mouseout event occurs only if the user taps on
another clickable item. Also, if the contents of the page changes on
the mousemove event, no subsequent events in the sequence are sent.
This behavior allows the user to tap in the new content.
The problem is that it's not clear what constitutes a content change.
Setting display:none removes the element from the document flow; setting display:block (or display:inline) will put it back into the document flow, which would be a content change akin to creating and adding a new element on the fly.
When you're changing opacity, the element is always in the document flow, just not visible.
Try using display:hidden rather than display:block. If I'm right, display:hidden won't cause you any trouble with double-taps either. Using "hidden" does not remove the element from the document flow, which is why there's a blank space equivalent to the size of the hidden object when the object is not visible.
https://www.w3.org/TR/CSS2/visuren.html#display-prop

How to add hover effect to img placed in parent container

How can I add a hover effect to the img after mouse is over link Text using CSS?
<div class="myTextContainer">
<p>
<a href="#">
<img height="128" width="128" title="icon1" alt="icon1" src="icon1.png" ">
</a>
</p>
<h2>
Text
</h2>
</div>
Try adding some JavaScript. In my case i added html attribute onmouseover and onmouseleave to call a javascript function. fun1 on hover and fun 2 onleave. I added id hover on my image and i said on each function to get the element of the id hover which is my image and change the backgroundColor='blue'. On hover i set it to blue and onleave i set it to red. You can change other elements like the src by doing style.src='here/put/the/image/source/img.png' and add different src on hover or leave. If you need more info leave a comment. Did this help?
function fun1(){
document.getElementById("hover").style.backgroundColor='blue';
}
function fun2(){
document.getElementById("hover").style.backgroundColor='red';
}
#hover{
background-color:red;
}
<div class="myTextContainer">
<a href="#">
<img id="hover" height="128" width="128" title="icon1" alt="icon1" src="icon1.png">
</a>
<h2>
Text
</h2>
</div>
-------- Or by doing this without script tag or file --------
#hover{
background-color:red;
}
<div class="myTextContainer">
<p>
<a href="#">
<img id="hover" height="128" width="128" title="icon1" alt="icon1" src="icon1.png">
</a>
</p>
<h2>
Text
</h2>
</div>
Change your HTML markup and put both, icon and text into one link.
<h2>
<a>
<img ...>
TEXT
</a>
</h2>
Than you can use simply
a:hover {color: red;} /* red text 'TEXT' */
a:hover img {border: 1px solid green}
Since h2 and p are siblings but you want to add hover on h2 img which is before p, you cannot do it with CSS. You need javascript:
document.querySelectorAll('a')[1].addEventListener('mouseover', fn, false);
document.querySelectorAll('a')[1].addEventListener('mouseout', fn2, false);
function fn(e) {
if(e.target.innerHTML == 'Text') {
document.querySelector('img[src="icon1.png"]').className = 'hover';
}
}
function fn2(e) {
if(e.target.innerHTML == 'Text') {
document.querySelector('img[src="icon.png"]').className = '';
}
}
you could declare:
.myTextContainer a:hover img {
// your CSS
}

How to exclude an element when using a link

I have an issue right now and i am curious if there is a possible way to solve this. I have 2 div's enclosed in href elements. The problem is that i want to exclude the <p> element. Is there a way to do this despite it being inside the href element? Thanks.
<a href= "sample.com">
<div class="1">
<p>Hello</p>
</div>
</a>
<a href= "test.com">
<div class="2">
<p>Hello</p>
</div>
</a>
Yes you can but I wouldn't advocate for it.
You could use CSS to remove the appearance of a link:
a{
text-decoration: none;
}
p{
cursor: default;
color: #000;
}
Then you could use preventDefault() to prevent the p from triggering the action on click:
$("p").click(function(e){
e.preventDefault();
});
FIDDLE
What you really should do is add another wrapper to contain your elements and then wrap your div with an a like so:
<div class="wrapper">
<a href="http://www.google.com" target="_blank">
<div class="1"></div>
</a>
<p>Hello</p>
</div>
$(function(){
$('p').click(function(){
alert($(this).attr('href'));
// or alert($(this).hash();
});
});

Combining MouseOn with CSS Link Hover

I’m using a combination of icons and text for some links in the sidebar on my website, but I want both the icon and text to change if the mouse hovers over either of them. Using MouseOn and ‘hover’ in my CSS file, I’ve managed to get this to work when the mouse hovers over the icon, but if the mouse only hovers over the text, only the text changes but not the icon as well. Does anybody know a way to do this please? A link to my site and the code I’m currently using are below. Thanks everybody.
http://www.retelevise.com
<span class="social-media-sidebar-panel">
<a href="https://www.facebook.com/re.televise" target="_external window fa">
<img src="http://www.retelevise.com/wp-content/themes/myownzee/branding/
socialmedia-facebook-1.png"
onmouseover="this.src='http://www.retelevise.com/wp-content/themes/myownzee/
branding/socialmedia-facebook-2.png'"
onmouseout="this.src='http://www.retelevise.com/wp-content/themes/myownzee/
branding/socialmedia-facebook-1.png'"
class="social-media-sidebar-icons" title="Facebook" alt="Facebook">
<span style="font-size: 0.8em">Facebook</span></a></span>
try moving your onmouseover and onmouseout events to anchor and change the 'this.' to reference the img by ID.
I've made several changes to the way you've done this:
Moved your styling and javascript to external files
Used JQuery for animations (simply easier)
This version now makes use of multiple images.
JSFiddle DEMO
HTML:
<span class="sm">
<a href="#" class="mediaLink">
<img class="mediaPic" data-hover="http://placehold.it/60/4477ee/ffffff" src="http://placehold.it/60/224499/ffffff"/>
<div class="mediaText"> Facebook</div>
</a>
</span>
<span class="sm">
<a href="#" class="mediaLink">
<img class="mediaPic" data-hover="http://placehold.it/60/ee9933/ffffff" src="http://placehold.it/60/777777/ffffff"/>
<div class="mediaText"> Stack Overflow</div>
</a>
</span>
<span class="sm">
<a href="#" class="mediaLink">
<img class="mediaPic" data-hover="http://placehold.it/60/66aaff/ffffff" src="http://placehold.it/60/3388aa/ffffff"/>
<div class="mediaText"> Twitter</div>
</a>
</span>
<span class="sm">
<a href="#" class="mediaLink">
<img class="mediaPic" data-hover="http://placehold.it/60/dd1122/ffffff" src="http://placehold.it/60/991122/ffffff"/>
<div class="mediaText"> YouTube</div>
</a>
</span>
JavaScript (Using JQuery):
$(document).ready( function() {
$(".mediaLink").on( {
mouseenter: function() {
$(this).children(".mediaPic").data("static", $(this).children(".mediaPic").attr("src"));
$(this).children(".mediaText").css("color", "orange");
$(this).children(".mediaPic").attr("src", $(this).children(".mediaPic").data("hover"));
}, mouseleave: function() {
$(this).children(".mediaText").css("color", "white");
$(this).children(".mediaPic").attr("src", $(this).children(".mediaPic").data("static"));
}
});
});
CSS:
.mediaLink {
display: block;
}
.mediaPic {
float: left;
width, height: 60px;
}
.mediaText {
height: 60px;
width: 150px;
padding-left: 10px;
line-height: 60px;
background: #242424;
color: white;
font-family: "Consolas"," Arial";
font-size: 18px;
float: left;
}
.sm {
margin: 5px;
float: left;
}
Explanation:
I'm making the <a> change its children (.mediaPic and .mediaText) when its being hovered over. On mouseenter is when the mouse is hovered over, and mouseleave is returning the <a> back to its regular state.
The part called data-hover is the url of the picture you wish to set the image to, where you leave src as the image you want to have as the default. When you hover over the image, the script will "remember" the original src and set it back to that when you leave the image (mouseleave).