skip to Main Content

I have a DOM with multiple horizontal scroll containers and prev next buttons. I’m not able to change the html so that’s what I got.

<div class="scroll_container"></div>
<div class="prev_button_wrapper">
 <button class="prev_button"></div>
</div>
<div class="next_button_wrapper">
 <button class="next_button"></div>
</div>

<div class="scroll_container"></div>
<div class="prev_button_wrapper">
 <button class="prev_button"></div>
</div>
<div class="next_button_wrapper">
 <button class="next_button"></div>
</div>
...

So far I got this.

jQuery(document).ready(function() {

 jQuery(".prev_button").click(
    function() {
        var thumbHolder = jQuery(".scroll_container");
        thumbHolder.scrollLeft(thumbHolder.scrollLeft() - 300);
    }
 );
 jQuery(".next_button").click(
    function() {
        var thumbHolder = jQuery(".scroll_container");
        thumbHolder.scrollLeft(thumbHolder.scrollLeft() + 300);
    }
 );
});

Of course the problem is, that the first prev and next buttons scroll all containers on the page. I already tried to use closest() but I couldn’t get it work.I’m at a very basic level with Java/jQuery and appreciate any help.

2

Answers


  1. To make your jQuery code work for each arrangement of parchment compartments and their comparing prev/next buttons, you want to utilize crossing techniques like nearest() and next() to focus on the particular holders and buttons connected with one another. Here is the changed code that ought to work accurately:

    <!-- First set of scroll -->
    <div class="scroll_container"></div>
    <div class="prev_button_wrapper">
      <button class="prev_button"></button>
    </div>
    <div class="next_button_wrapper">
      <button class="next_button"></button>
    </div>
    
    <!-- Second set of scroll -->
    <div class="scroll_container"></div>
    <div class="prev_button_wrapper">
      <button class="prev_button"></button>
    </div>
    <div class="next_button_wrapper">
      <button class="next_button"></button>
    </div>
    
    ...
    
    
    jQuery(document).ready(function() {
      jQuery(".prev_button").click(function() {
        var container = jQuery(this).closest('.prev_button_wrapper').prev('.scroll_container');
        container.scrollLeft(container.scrollLeft() - 300);
      });
    
      jQuery(".next_button").click(function() {
        var container = jQuery(this).closest('.next_button_wrapper').prev('.scroll_container');
        container.scrollLeft(container.scrollLeft() + 300);
      });
    });
    

    With the changes above, when you click on a particular prev_button, it will view as the comparing .scroll_container component utilizing closest('.prev_button_wrapper') and afterward use prev('.scroll_container') to get the compartment that precedes the clicked button. Additionally, for the next_button, it will view as the comparing .scroll_container component utilizing closest('.next_button_wrapper') and afterward use prev('.scroll_container') to get the holder that precedes the next_button.

    Along these lines, the snap occasions will focus on the right parchment compartment connected with each arrangement of prev/next buttons.

    Login or Signup to reply.
  2. Unfortunately, because the .scroll_container isn’t wrapped within the same parent as any individual <button> group, using closest() to find the relevant element will either fail – and simply not find the element, based on the selector passed to the method – or alternatively – depending on the selector… – find all .scroll_container elements.

    This being the case, we’re required to use a somewhat complex mix of closest(), prevAll(), first() and find(). This would – of course – be much easier if the HTML could be adjusted, even if only in the JavaScript/jQuery to wrap elements together.

    Without that option, though, this is the best approach I could think of; there are explanatory comments in the code:

    // here we retrieve all <button> elements, and use the on() method to
    // bind the anonymous function as the event-handler for those buttons
    // that match the supplied selector list:
    $('button').on('click', function() {
      // the clicked <button>:
      let btn = $(this),
        // the first ancestor of the clicked <button> that matches the
        // supplied CSS selector:
        parent = $(this).closest('div[class$="_wrapper"]'),
        // if the <button> has the class of 'prev_button', we
        // return -100 as the scrollDistance; otherwise - because we
        // restricted the event-handler to either '.prev_button' or
        // 'next_button', the distance will be 100:
        scrollDistance = btn.hasClass('prev_button') ? -100 : 100,
        // this would be easier if the <button> elements and the
        // scrolling element were all wrapped in the same element,
        // and distinct from the other elements; but here we navigate
        // from the ancestor element using prevAll() to find all
        // previous siblings that match the supplied CSS selector,
        // along with the first() method to retain only the first of
        // those siblings; in that element we use find() to find
        // the descendant child-element that is the :first-child;
        // in this demo that's the element we want to scroll, in your
        // case this may be a different element so bear that in mind:
        scrollElement = parent.prevAll('.scroll_container').first().find('> :first-child'),
        // we retrieve the current scroll position of the element to
        // scroll, using the scrollLeft() method with no argument,
        // which causes it to get - rather than set - the scrollLeft
        // position:
        currentScroll = scrollElement.scrollLeft();
    
      // we then use scrollLeft() with an argument, in order to
      // have it set the scrollLeft position, to a distance of
      // the currentScroll plus the scrollDistance:
      scrollElement.scrollLeft(currentScroll + scrollDistance);
    });
    *,
    ::before,
    ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    ol,
    li {
      list-style-type: none;
    }
    
    ol {
      display: flex;
      flex-flow: row nowrap;
      gap: 2rem;
      overflow-y: hidden;
      padding-block: 1rem;
      padding-inline: 2rem;
    }
    
    li {
      border: 2px solid currentColor;
      border-radius: 0.2rem;
      flex-basis: 2rem;
      padding: 0.5rem;
    }
    
    .prev_button_wrapper,
    .next_button_wrapper {
      display: inline-block;
    }
    
    button {
      font-size: 2rem;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="scroll_container">
      <!-- I'm aware that you can't change your HTML, this is simply dummy content,
           replace with your real content in development/production: -->
      <ol>
        <li>a</li>
        <li>b</li>
        <li>c</li>
        <li>d</li>
        <li>e</li>
        <li>f</li>
        <li>g</li>
        <li>h</li>
        <li>i</li>
        <li>j</li>
        <li>k</li>
        <li>l</li>
        <li>m</li>
        <li>n</li>
        <li>o</li>
        <li>p</li>
        <li>q</li>
        <li>r</li>
        <li>s</li>
        <li>t</li>
        <li>u</li>
        <li>v</li>
        <li>w</li>
        <li>x</li>
        <li>y</li>
        <li>z</li>
      </ol>
    </div>
    <div class="prev_button_wrapper">
      <button class="prev_button">&laquo;</button>
    </div>
    
    <div class="next_button_wrapper">
      <button class="next_button">&raquo;</button>
    </div>
    
    
    <div class="scroll_container">
    
      <ol>
        <li>a</li>
        <li>b</li>
        <li>c</li>
        <li>d</li>
        <li>e</li>
        <li>f</li>
        <li>g</li>
        <li>h</li>
        <li>i</li>
        <li>j</li>
        <li>k</li>
        <li>l</li>
        <li>m</li>
        <li>n</li>
        <li>o</li>
        <li>p</li>
        <li>q</li>
        <li>r</li>
        <li>s</li>
        <li>t</li>
        <li>u</li>
        <li>v</li>
        <li>w</li>
        <li>x</li>
        <li>y</li>
        <li>z</li>
      </ol>
    </div>
    <div class="prev_button_wrapper">
      <button class="prev_button">&laquo;</button>
    </div>
    
    <div class="next_button_wrapper">
      <button class="next_button">&raquo;</button>
    </div>

    JS Fiddle demo.

    References:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search