How to allow infinite scrolling in the both directions with md-virtual-repeat?
Asked Answered
L

1

7

I've implemented an infinite horizontal scroll using md-virtual-repeat. It fetches 25 records each time when needed when I scroll to the right.

<md-virtual-repeat-container flex md-orient-horizontal>
  <div md-virtual-repeat="item in $ctrl.infiniteItems" md-on-demand>
    {{ item.date }}
  </div>
</md-virtual-repeat-container>

Essentially it's a horizontal list of dates (with other information) that you can scroll in. You scroll to the future dates. Works fine.

Now, I want to also scroll to the left where the dates of the past are.

I'm looking for a way to start in the middle (where today's date is). I've tried setting md-top-index by a value on the controller, but it gets reset to a low number after the first page is fetched from the server.

<md-virtual-repeat-container flex md-orient-horizontal md-top-index="$ctrl.topIndex">
  <div md-virtual-repeat="item in $ctrl.infiniteItems" md-on-demand>
    {{ item.date }}
  </div>
</md-virtual-repeat-container>

How can I configure md-virtual-repeat-container and md-virtual-repeat to allow scrolling to the left as well as to the right?

Update: Here's a sandbox with Codepen of the situation that I'd like to accomodate with a button to scroll leftwards. https://codepen.io/christiaanwesterbeek/pen/pLRQgg

Update2: Setting an md-top-index to some positive integer allows scrolling in both directions. But the example given at the angular material site with md-top-index is not about infinite scrolling. The solution to my question is where md-top-index meets infinite scrolling.

Lashanda answered 15/3, 2018 at 18:43 Comment(0)
I
0

well .. to answer you question :

you can allow scrolling in the reverse direction of md-virtual-repeat by changing the body tag of your html document to <body dir="rtl">

a quick rundown :

i looked for this everywhere but i couldn't find anything and i assume you did too, so i downloaded angular-material.js from angular cdn locally to see how they handle this, here's a snippet :

VirtualRepeatContainerController.prototype.handleScroll_ = function() {
  var ltr = document.dir != 'rtl' && document.body.dir != 'rtl';
  if(!ltr && !this.maxSize) {
    this.scroller.scrollLeft = this.scrollSize;
    this.maxSize = this.scroller.scrollLeft;
  }
  var offset = this.isHorizontal() ?
      (ltr?this.scroller.scrollLeft : this.maxSize - this.scroller.scrollLeft)
      : this.scroller.scrollTop;

  if (offset === this.scrollOffset || offset > this.scrollSize - this.size) return;

  var itemSize = this.repeater.getItemSize();
  if (!itemSize) return;

  var numItems = Math.max(0, Math.floor(offset / itemSize) - NUM_EXTRA);

  var transform = (this.isHorizontal() ? 'translateX(' : 'translateY(') +
      (!this.isHorizontal() || ltr ? (numItems * itemSize) : - (numItems * itemSize))  + 'px)';

  this.scrollOffset = offset;
  this.offsetter.style.webkitTransform = transform;
  this.offsetter.style.transform = transform;

  if (this.bindTopIndex) {
    var topIndex = Math.floor(offset / itemSize);
    if (topIndex !== this.topIndex && topIndex < this.repeater.getItemCount()) {
      this.topIndex = topIndex;
      this.bindTopIndex.assign(this.$scope, topIndex);
      if (!this.$rootScope.$$phase) this.$scope.$digest();
    }
  }

  this.repeater.containerUpdated();
};

this is how i found that they rely on the body's direction to direct the infinit scrolling, so if you don't want to change the direction of your html document, you'll have to download it, edit this part and use it instead of the cdn , however .. it won't work as expected;

in normal situation, scrolling from left to right will increment the this.scrollLeft variable and as you can see in the snippet it's used everywhere, it will increment the offset and the translateX() and everything will fall into the right place,

but if you're scrolling from right to the left, the handleScroll_ function will set the this.scrollOfsset to the width of the view and as you scroll to left, this.scrollLeft will decrease instead of increasing and once you reach the end of your first 25 everything will break apart,

i tried console.log of all the variables inside and compared the rtl with the ltr to see when and where things break, i tried to play around with the values and operations but no success, feel free to do the same and experiment maybe i missed something ( but hey, the question is only about changing the direction right ? :P )

i would recommend you to go for something else ( like the ones in the comments above )

i hope this helps or at least gives you an idea, good luck.

EDIT :

since this depends on the body's direction, you can either scroll left or right, not both, even if you set md-top-index and start in the middle ( withdir="ltr" ) , you'll only have infinit scrolling on one side ( to the right ) if you go back, it's just displaying old already loaded data,

you can take a look at VirtualRepeatController.prototype.virtualRepeatUpdate_ inside the js file to see how it adds the new blocks and update indexes and the scroll.

on a side note: people wanted this for reverse vertical scrolling ( for chat apps ) and there are open issues but it's not likely to be added since they moved to angular 2.x and above

bottom line is : if you want scrolling on both sides with only configuration, i'm afraid you can't, and if you absolutely want this you're going to have to modify angular-material.js to fit your needs.

Irrawaddy answered 24/3, 2018 at 6:20 Comment(6)
It looks like you assumed that I need only scrolling to the left, but I actually need scrolling to both directions. This rtl approach does not allow scrolling in both directions.Lashanda
i edited my answer to be more precise, i know you wanted scrolling on both sides, maybe i just didn't express myself very well, but i elaborated on how the scrolling to the left can be difficult, adding blocks to the start ( the left ) is gonna mess up the indexes and everything else, because with dir="rtl" the new blocks are added to the end and it's just a matter of direction and the blocks are not really added to the startIrrawaddy
Setting a md-top-index to some positive integer allows scrolling to both directions. But the example given at the angular material site with md-top-index is not about infinite scrolling. The solution to my question is where md-top-index meets inifite scrolling. I hope I can trigger you to own the solution and earn the bounty :)Lashanda
hmm yeah i see what you mean, setting md-top-index will jump to that index ( i saw it here codepen.io/colinskow/pen/jbVaRj ) and mentioned it the edit, but this will stop when it goes back and reaches the start, i thought the idea is to scroll infinitely in both directions, like when you scroll to the left and you reach 0 will start seeing -1,-2,-3 ..etc. i found the example in the link but i didn't think about adding setting up md-top-index to the answer because it's not infinite scrolling , i was hoping to get the bounty as it will be my first but it's up to you to decide :)Irrawaddy
I appreciate your effort, but your answer is more like a log of your investigation. I will award the bounty to a real solution.Lashanda
There are 24 hours left for me to award the bounty. If you can get this to work within that period I will award the bounty to you. After the 24 hours, I can't award it to you anymore... I know there's a solution without modifying angular-material.js. There's just some smartness that has to be implemented in the getItemAtIndex, fetchMoreItems_ methods this. Probably 2 arrays are involved. One for going one direction and one for going the opposite direction.Lashanda

© 2022 - 2024 — McMap. All rights reserved.