RoyBarOn
RoyBarOn

Reputation: 987

How to scroll to top li element by click?

I have a ul li of links (left) which once they clicked - i want to navigate and scroll the target element to the top of the right ul. I've tried .scrollTop(), but it's not working... In the example below, i set border to the element which needs to be scrolled to top. I guess i need to calculate to element's position and subtract it from the ul scroll height..

$(document).ready(function() {

  var left = $('ul.list-group > li');
  var right = $('.right > p');

  left.each(function() {
    var left_id = $(this).attr('object_id');
    $(this).on('click', function() {
      right.each(function(){
      if(left_id == $(this).attr('object_id'))
        $(this).css({"border":"1px solid red"});

      $('ul.list-group').animate({
        scrollTop: $(this).offset().top
      }, 2000);

    });
  });
});
});
.wrap {
  display: flex;
}

.right {
  overflow: scroll;
  height: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">

  <div class="left">

    <ul class="list-group">
      <li class="list-group-item" object_id="1">Cras justo odio</li>
      <li class="list-group-item" object_id="2">Dapibus ac facilisis in</li>
      <li class="list-group-item" object_id="3">Morbi leo risus</li>
      <li class="list-group-item" object_id="4">Vestibulum at eros</li>
      <li class="list-group-item" object_id="5">Cras justo odio</li>
      <li class="list-group-item" object_id="6">Dapibus ac facilisis in</li>
      <li class="list-group-item" object_id="7">Morbi leo risus</li>
      <li class="list-group-item" object_id="8">Porta ac consectetur ac</li>
      <li class="list-group-item" object_id="9">Vestibulum at eros</li>
      <li class="list-group-item" object_id="10">Porta ac consectetur ac</li>
    </ul>
  </div>
  <div class="right">
    <p object_id="1">Cras justo odio</p>
    <p object_id="2">Dapibus ac facilisis in</p>
    <p object_id="3">Porta ac consectetur ac</p>
    <p object_id="4">Vestibulum at eros</p>
    <p object_id="5">Cras justo odio</p>
    <p object_id="6">Dapibus ac facilisis in</p>
    <p object_id="7">Morbi leo risus</p>
    <p object_id="8">Porta ac consectetur ac</p>
    <p object_id="9">Vestibulum at eros</p>
    <p object_id="10">Vestibulum at eros</p>
  </div>
</div>

Upvotes: 2

Views: 1574

Answers (2)

Mohamed-Yousef
Mohamed-Yousef

Reputation: 24001

1st: It'll be hard to control animate() while your p elements has auto margin

2nd: You need to loop through all the .right > p elements to get its offset().top before click event not inside it Actually I don't know why offset change inside the click event each time the click run

3rd it will be better to use .stop().animate()

See the code below

$(document).ready(function() {
  var left = $('ul.list-group > li');  // left li
  var right = $('.right > p');      // right p
  var rightOffsets = [];    // array to save p offsets top
  right.each(function(){    // loop through p elements
    var getAttribute = $(this).attr('object_id'); // get this p element object_id
    rightOffsets[getAttribute] =  $(this).offset().top - $('.right').offset().top;  // get this p offset top minus the right div offset top 
  });
  left.on('click', function() {
    var left_id = $(this).attr('object_id');   // get object_id
    $('.right > p[object_id='+left_id+']').css('background','red');
    //alert(rightOffsets[left_id]);
    $('.right').stop().animate({
      scrollTop: rightOffsets[left_id] // animate the right to the offest().top for the right > p
    }, 1000);
  });
});
.wrap {
  display: flex;
}

.right {
  overflow: scroll;
  height: 100px;
}
p{
  margin : 0;
  padding : 10px;
  height : 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrap">

<div class="left">

  <ul class="list-group">
    <li class="list-group-item" object_id="1">Cras justo odio</li>
    <li class="list-group-item" object_id="2">Dapibus ac facilisis in</li>
    <li class="list-group-item" object_id="3">Morbi leo risus</li>
    <li class="list-group-item" object_id="4">Vestibulum at eros</li>
    <li class="list-group-item" object_id="5">Cras justo odio</li>
    <li class="list-group-item" object_id="6">Dapibus ac facilisis in</li>
    <li class="list-group-item" object_id="7">Morbi leo risus</li>
    <li class="list-group-item" object_id="8">Porta ac consectetur ac</li>
    <li class="list-group-item" object_id="9">Vestibulum at eros</li>
    <li class="list-group-item" object_id="10">Porta ac consectetur ac</li>
  </ul>
</div>
<div class="right">
  <p object_id="1">Cras justo odio</p>
  <p object_id="2">Dapibus ac facilisis in</p>
  <p object_id="3">Porta ac consectetur ac</p>
  <p object_id="4">Vestibulum at eros</p>
  <p object_id="5">Cras justo odio</p>
  <p object_id="6">Dapibus ac facilisis in</p>
  <p object_id="7">Morbi leo risus</p>
  <p object_id="8">Porta ac consectetur ac</p>
  <p object_id="9">Vestibulum at eros</p>
  <p object_id="10">Vestibulum at eros</p>
</div>
</div>

Upvotes: 2

Tomasz Bubała
Tomasz Bubała

Reputation: 2153

I guess what you're trying to do is scroll the right section. I left you're code as is with minor changes so you can understand what was wrong. The code now animates $(".right") and it's now outside of each function. With the way you had it it was actually animating 10 times, each time for one paragraph. And last thing i changed was to add {} to if statement. I leave the animation offset for you to figure out

$(document).ready(function() {
  var left = $('ul.list-group > li');
  var right = $('.right > p');

  left.each(function() {
     var left_id = $(this).attr('object_id');
     $(this).on('click', function() {
       right.each(function(){
         if(left_id == $(this).attr('object_id')) {
           $(this).css({"border":"1px solid red"});
         }
       });
       $('.right').animate({
         scrollTop: $(this).offset().top
       }, 2000);
      });
    });
  });

Upvotes: 1

Related Questions