Natalya
Natalya

Reputation: 123

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

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>

Upvotes: 0

Views: 79

Answers (1)

Don&#39;t Panic
Don&#39;t Panic

Reputation: 14520

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>

Upvotes: 0

Related Questions