Skip to content

How can I get this working for horizontal scrolling? #79

@PatrLind

Description

@PatrLind

I want to have a infinite single line horizontal scrolling container, but I cannot seem to get this working with this component. Is it possible or do I need to look elsewhere?

Activity

a-kriya

a-kriya commented on Sep 16, 2017

@a-kriya
Contributor

Yeah, that isn't currently possible with this component.

PatrLind

PatrLind commented on Sep 16, 2017

@PatrLind
Author

Ok, I see, how difficult would you think it would be to implement? I have not looked at the code yet, but maybe I could try to modify it myself and perhaps make a PR if it works out ok...

a-kriya

a-kriya commented on Sep 16, 2017

@a-kriya
Contributor

This particular block of code currently assumes vertical scrolling -- uses scrollTop/yOffsets/innerHeight/top-bottom positions.

Perhaps if you created another method that would be used for a horizontal scrolling mode, then it may be something @PeachScript want to include in this component.

PeachScript

PeachScript commented on Sep 17, 2017

@PeachScript
Owner

@PatrLind @Syn-zeta thank you, please give me some time to think about it.

For the temporary solution, you can use the extend feature to override the getCurrentDistance method and make it support calculate horizontal distance.

PatrLind

PatrLind commented on Sep 18, 2017

@PatrLind
Author

谢谢@PeachScript , I will give it a try :)

PatrLind

PatrLind commented on Sep 18, 2017

@PatrLind
Author

It seems my test component I made works as I need it to.
In case anyone can make use of it, here it is (TypeScript):

import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import InfiniteLoading from 'vue-infinite-loading'

@Component({
  extends: InfiniteLoading,
})
export class InfiniteLoadingExtra extends Vue {
  direction: 'top' | 'left' | 'right' | 'bottom'
  scrollParent: any
  forceUseInfiniteWrapper: boolean | null

  getCurrentDistance(this: InfiniteLoadingExtra) {
    let distance: number = 0
    if (this.direction === 'top') {
      distance = isNaN(this.scrollParent.scrollTop) ?
        this.scrollParent.pageYOffset :
        this.scrollParent.scrollTop
    } else if (this.direction === 'left') {
      distance = isNaN(this.scrollParent.scrollLeft) ?
        this.scrollParent.pageXOffset :
        this.scrollParent.scrollLeft
    } else if (this.direction === 'bottom') {
      const infiniteElmOffsetTopFromBottom = this.$el.getBoundingClientRect().top
      const scrollElmOffsetTopFromBottom = this.scrollParent === window ?
        window.innerHeight :
        this.scrollParent.getBoundingClientRect().bottom
      distance = infiniteElmOffsetTopFromBottom - scrollElmOffsetTopFromBottom
    } else if (this.direction === 'right') {
      const infiniteElmOffsetLeftFromRight = this.$el.getBoundingClientRect().left
      const scrollElmOffsetLeftFromRight = this.scrollParent === window ?
        window.innerWidth :
        this.scrollParent.getBoundingClientRect().right
      distance = infiniteElmOffsetLeftFromRight - scrollElmOffsetLeftFromRight
    }
    return distance
  }

  getScrollParent(elm = this.$el): any {
    let result: any | undefined
    if (elm.tagName === 'BODY') {
      result = window
    } else if (!this.forceUseInfiniteWrapper && (
      ((this.direction === 'top'  || this.direction === 'bottom') && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY!) > -1) ||
      ((this.direction === 'left' || this.direction === 'right')  && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowX!) > -1)
    )) {
      result = elm
    } else if (elm.hasAttribute('infinite-wrapper') || elm.hasAttribute('data-infinite-wrapper')) {
      result = elm
    }
    return result || this.getScrollParent(elm.parentNode as any)
  }
}

Note that I needed to get the latest source code for this to work. The one I got thru npm was not extendable.

PeachScript

PeachScript commented on Sep 19, 2017

@PeachScript
Owner

Haha, @PatrLind your Chinese is excellent! Thanks for your solution!

demonmind

demonmind commented on Oct 13, 2017

@demonmind

@PatrLind this is something I need to use in my project too, but we do not use typescript. Do you have a JS snippet i can use?

demonmind

demonmind commented on Oct 13, 2017

@demonmind

I cant get the @Component({....}) to work. Webpack fails to compile

PatrLind

PatrLind commented on Oct 16, 2017

@PatrLind
Author

@demonmind sorry for that, I made a vanilla JS version for you, but I have not tested it very well, so please give it a try:

<script>
import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import InfiniteLoading from 'vue-infinite-loading'

export default {
  name: 'infinite-loading-extra',
  extends: InfiniteLoading,
  methods: {
    getCurrentDistance() {
      let distance = 0
      if (this.direction === 'top') {
        distance = isNaN(this.scrollParent.scrollTop) ?
          this.scrollParent.pageYOffset :
          this.scrollParent.scrollTop
      } else if (this.direction === 'left') {
        distance = isNaN(this.scrollParent.scrollLeft) ?
          this.scrollParent.pageXOffset :
          this.scrollParent.scrollLeft
      } else if (this.direction === 'bottom') {
        const infiniteElmOffsetTopFromBottom = this.$el.getBoundingClientRect().top
        const scrollElmOffsetTopFromBottom = this.scrollParent === window ?
          window.innerHeight :
          this.scrollParent.getBoundingClientRect().bottom
        distance = infiniteElmOffsetTopFromBottom - scrollElmOffsetTopFromBottom
      } else if (this.direction === 'right') {
        const infiniteElmOffsetLeftFromRight = this.$el.getBoundingClientRect().left
        const scrollElmOffsetLeftFromRight = this.scrollParent === window ?
          window.innerWidth :
          this.scrollParent.getBoundingClientRect().right
        distance = infiniteElmOffsetLeftFromRight - scrollElmOffsetLeftFromRight
      }
      return distance
    },

    getScrollParent(elm = this.$el) {
      let result
      if (elm.tagName === 'BODY') {
        result = window
      } else if (!this.forceUseInfiniteWrapper && (
        ((this.direction === 'top'  || this.direction === 'bottom') && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) ||
        ((this.direction === 'left' || this.direction === 'right')  && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowX) > -1)
      )) {
        result = elm
      } else if (elm.hasAttribute('infinite-wrapper') || elm.hasAttribute('data-infinite-wrapper')) {
        result = elm
      }
      return result || this.getScrollParent(elm.parentNode)
    }
  }
}

</script>
demonmind

demonmind commented on Oct 16, 2017

@demonmind

Thank you! will try it and let you know

yagogak

yagogak commented on Mar 1, 2018

@yagogak

@PatrLind this is working !, dont forget to set props direction to right on your infinite-loading-extra component

rivajunior

rivajunior commented on Aug 5, 2019

@rivajunior

@demonmind sorry for that, I made a vanilla JS version for you, but I have not tested it very well, so please give it a try:

<script>
import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import InfiniteLoading from 'vue-infinite-loading'

export default {
  name: 'infinite-loading-extra',
  extends: InfiniteLoading,
  methods: {
    getCurrentDistance() {
      let distance = 0
      if (this.direction === 'top') {
        distance = isNaN(this.scrollParent.scrollTop) ?
          this.scrollParent.pageYOffset :
          this.scrollParent.scrollTop
      } else if (this.direction === 'left') {
        distance = isNaN(this.scrollParent.scrollLeft) ?
          this.scrollParent.pageXOffset :
          this.scrollParent.scrollLeft
      } else if (this.direction === 'bottom') {
        const infiniteElmOffsetTopFromBottom = this.$el.getBoundingClientRect().top
        const scrollElmOffsetTopFromBottom = this.scrollParent === window ?
          window.innerHeight :
          this.scrollParent.getBoundingClientRect().bottom
        distance = infiniteElmOffsetTopFromBottom - scrollElmOffsetTopFromBottom
      } else if (this.direction === 'right') {
        const infiniteElmOffsetLeftFromRight = this.$el.getBoundingClientRect().left
        const scrollElmOffsetLeftFromRight = this.scrollParent === window ?
          window.innerWidth :
          this.scrollParent.getBoundingClientRect().right
        distance = infiniteElmOffsetLeftFromRight - scrollElmOffsetLeftFromRight
      }
      return distance
    },

    getScrollParent(elm = this.$el) {
      let result
      if (elm.tagName === 'BODY') {
        result = window
      } else if (!this.forceUseInfiniteWrapper && (
        ((this.direction === 'top'  || this.direction === 'bottom') && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) ||
        ((this.direction === 'left' || this.direction === 'right')  && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowX) > -1)
      )) {
        result = elm
      } else if (elm.hasAttribute('infinite-wrapper') || elm.hasAttribute('data-infinite-wrapper')) {
        result = elm
      }
      return result || this.getScrollParent(elm.parentNode)
    }
  }
}

</script>

I have formated the code, but even that way, didn't work

import InfiniteLoading from 'vue-infinite-loading';

export default {
  name: 'InfiniteLoadingExtra',
  extends: InfiniteLoading,
  methods: {
    getCurrentDistance() {
      switch (this.direction) {
        case 'top':
          return isNaN(this.scrollParent.scrollTop)
            ? this.scrollParent.pageYOffset
            : this.scrollParent.scrollTop;
        case 'left':
          return isNaN(this.scrollParent.scrollLeft)
            ? this.scrollParent.pageXOffset
            : this.scrollParent.scrollLeft;
        case 'bottom':
          return (
            this.$el.getBoundingClientRect().top -
            (this.scrollParent === window
              ? window.innerHeight
              : this.scrollParent.getBoundingClientRect().bottom)
          );
        case 'right':
          return (
            this.$el.getBoundingClientRect().left -
            (this.scrollParent === window
              ? window.innerWidth
              : this.scrollParent.getBoundingClientRect().right)
          );
        default:
          return 0;
      }
    },
    getScrollParent(elm = this.$el) {
      if (elm.tagName === 'BODY') {
        return window;
      }

      if (
        !this.forceUseInfiniteWrapper &&
        (((this.direction === 'top' || this.direction === 'bottom') &&
          ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) ||
          ((this.direction === 'left' || this.direction === 'right') &&
            ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowX) > -1))
      ) {
        return elm;
      }

      if (
        elm.hasAttribute('infinite-wrapper') ||
        elm.hasAttribute('data-infinite-wrapper')
      ) {
        return elm;
      }

      return this.getScrollParent(elm.parentNode);
    }
  }
};
vesper8

vesper8 commented on May 2, 2020

@vesper8

works great! This should be merged into the core @PeachScript

@rivajunior I think maybe it's not working for you because you didn't set the direction? I guess it was not mentioned anywhere but in order for this to work with horizontal scrolling you have to set the direction to "right" because otherwise it defaults to "bottom"

like so:

          <InfiniteScrollingHorizontal
            direction="right"
            @infinite="infiniteHandler"
          />
vesper8

vesper8 commented on May 2, 2020

@vesper8

One thing however is that when using horizontal scrolling, it only works if I trigger the first call to infiniteHandler manually.. which results in some warnings in the debug console Uncaught (in promise) TypeError: Cannot read property 'loaded' of undefined but it does otherwise seem to work fine

I don't have this problem with vertical scrolling.

Did you have the same problem @PatrLind with having to trigger the first load manually? If not.. any insight on how you got around that?

Thanks!

joe94113

joe94113 commented on Dec 28, 2022

@joe94113

@demonmind sorry for that, I made a vanilla JS version for you, but I have not tested it very well, so please give it a try:

<script>
import Vue from 'vue'
import { Component } from 'vue-property-decorator'
import InfiniteLoading from 'vue-infinite-loading'

export default {
  name: 'infinite-loading-extra',
  extends: InfiniteLoading,
  methods: {
    getCurrentDistance() {
      let distance = 0
      if (this.direction === 'top') {
        distance = isNaN(this.scrollParent.scrollTop) ?
          this.scrollParent.pageYOffset :
          this.scrollParent.scrollTop
      } else if (this.direction === 'left') {
        distance = isNaN(this.scrollParent.scrollLeft) ?
          this.scrollParent.pageXOffset :
          this.scrollParent.scrollLeft
      } else if (this.direction === 'bottom') {
        const infiniteElmOffsetTopFromBottom = this.$el.getBoundingClientRect().top
        const scrollElmOffsetTopFromBottom = this.scrollParent === window ?
          window.innerHeight :
          this.scrollParent.getBoundingClientRect().bottom
        distance = infiniteElmOffsetTopFromBottom - scrollElmOffsetTopFromBottom
      } else if (this.direction === 'right') {
        const infiniteElmOffsetLeftFromRight = this.$el.getBoundingClientRect().left
        const scrollElmOffsetLeftFromRight = this.scrollParent === window ?
          window.innerWidth :
          this.scrollParent.getBoundingClientRect().right
        distance = infiniteElmOffsetLeftFromRight - scrollElmOffsetLeftFromRight
      }
      return distance
    },

    getScrollParent(elm = this.$el) {
      let result
      if (elm.tagName === 'BODY') {
        result = window
      } else if (!this.forceUseInfiniteWrapper && (
        ((this.direction === 'top'  || this.direction === 'bottom') && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) ||
        ((this.direction === 'left' || this.direction === 'right')  && ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowX) > -1)
      )) {
        result = elm
      } else if (elm.hasAttribute('infinite-wrapper') || elm.hasAttribute('data-infinite-wrapper')) {
        result = elm
      }
      return result || this.getScrollParent(elm.parentNode)
    }
  }
}

</script>

I have formated the code, but even that way, didn't work

import InfiniteLoading from 'vue-infinite-loading';

export default {
  name: 'InfiniteLoadingExtra',
  extends: InfiniteLoading,
  methods: {
    getCurrentDistance() {
      switch (this.direction) {
        case 'top':
          return isNaN(this.scrollParent.scrollTop)
            ? this.scrollParent.pageYOffset
            : this.scrollParent.scrollTop;
        case 'left':
          return isNaN(this.scrollParent.scrollLeft)
            ? this.scrollParent.pageXOffset
            : this.scrollParent.scrollLeft;
        case 'bottom':
          return (
            this.$el.getBoundingClientRect().top -
            (this.scrollParent === window
              ? window.innerHeight
              : this.scrollParent.getBoundingClientRect().bottom)
          );
        case 'right':
          return (
            this.$el.getBoundingClientRect().left -
            (this.scrollParent === window
              ? window.innerWidth
              : this.scrollParent.getBoundingClientRect().right)
          );
        default:
          return 0;
      }
    },
    getScrollParent(elm = this.$el) {
      if (elm.tagName === 'BODY') {
        return window;
      }

      if (
        !this.forceUseInfiniteWrapper &&
        (((this.direction === 'top' || this.direction === 'bottom') &&
          ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowY) > -1) ||
          ((this.direction === 'left' || this.direction === 'right') &&
            ['scroll', 'auto'].indexOf(getComputedStyle(elm).overflowX) > -1))
      ) {
        return elm;
      }

      if (
        elm.hasAttribute('infinite-wrapper') ||
        elm.hasAttribute('data-infinite-wrapper')
      ) {
        return elm;
      }

      return this.getScrollParent(elm.parentNode);
    }
  }
};

I use this code but it doesn't work.

I set the distance to the right, but the return value is less than 100, so the scroll loading event is always triggered.

The following is my template code, and version vue-infinite-loading": "^2.4.5

Can someone help me? Thanks

<template>
    <section>
        <div class="scroll">
            <div>
                <div class="item" v-for="item in items">
                    {{ item }}
                </div>
                <InfiniteLoadingExtra
                    direction="right"
                    @infinite="infiniteHandler"
                    ref="infiniteLoading"
                >
                </InfiniteLoadingExtra>
            </div>
        </div>
    </section>
</template>

<style scoped>
.scroll {
    white-space: nowrap;
    overflow-x: scroll;
}

.item {
    min-width: 500px;
    min-height: 50px;
    background-color: aqua;
    border-right: 1px solid;
    white-space: nowrap;
    display: inline-block;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @demonmind@vesper8@yagogak@PatrLind@PeachScript

        Issue actions

          How can I get this working for horizontal scrolling? · Issue #79 · PeachScript/vue-infinite-loading