Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"loaded" doesn't stop loading #55

Closed
DaveSanders opened this issue Jun 3, 2017 · 51 comments
Closed

"loaded" doesn't stop loading #55

DaveSanders opened this issue Jun 3, 2017 · 51 comments
Labels

Comments

@DaveSanders
Copy link

v2.1.3 - for some reason the "loaded" emit isn't stopping it from continuing to load results down the page. I'm pretty sure this was working before, but I can't figure out why this is happening.

So, basically even though I haven't scrolled down, it keeps hitting my server and loading more results. Here's my onInfinite function:

onInfinite () {
        api.tracks.get(PAGE_AMOUNT, this.tracks.length, tr => {
          console.log(`TRACKS: ${this.tracks.length}`)

          if (tr.length > 0) {
            this.tracks = this.tracks.concat(tr)
            if (tr.length < PAGE_AMOUNT) {
              this.$refs.infiniteLoading.$emit('$InfiniteLoading:complete')
            } else {
              this.$refs.infiniteLoading.$emit('$InfiniteLoading:loaded')
            }
          } else {
            this.$refs.infiniteLoading.$emit('$InfiniteLoading:complete')
          }
        })
      }

My template:

<template>
  <div id="track-list">
    <TrackItem v-for='(track, index) in tracks' :track='track' :index="index" :key='track.id'/>
    <infinite-loading :on-infinite="onInfinite" ref="infiniteLoading" spinner="waveDots"></infinite-loading>
  </div>
</template>

I did put console logs in and it IS hitting that else where it sends the loaded emit. I also changed it to :complete and it stopped calling at that point in the code. So it is emitting, it just seems like its not caring - or for some reason it thinks that its scrolled down.

Anything I'm doing wrong? Or any ideas on how to debug it further?

@DaveSanders
Copy link
Author

Simplified the onInfinite, but same result:

 onInfinite () {
        api.tracks.get(PAGE_AMOUNT, this.tracks.length, tr => {
          if (tr.length > 0) {
            this.tracks = this.tracks.concat(tr)
            console.log(`TRACKS: ${this.tracks.length}`)
            this.$refs.infiniteLoading.$emit('$InfiniteLoading:loaded')
          } else {
            this.$refs.infiniteLoading.$emit('$InfiniteLoading:complete')
          }
        })
      }

@PeachScript
Copy link
Owner

PeachScript commented Jun 3, 2017

I have changed the distance calculation method since v2.1.2, perhaps there has something wrong in the latest version if you were using a version earlier than v2.1.2 before, could you reproduce this problem on JSFiddle or other website like it?

@Akari1987
Copy link

When I use in nested component, I have same issue.

@Akari1987
Copy link

I'm sorry it was my misunderstanding. I used vue within Laravel, so it may be caused by laravel blade tempalte in my case :)

@PenAndPapers
Copy link

PenAndPapers commented Jul 4, 2017

I currently experiencing this kind of issue, it creates multiple request during page loading I'm using Laravel 5.4 and axois. Below is my JS code

axios.get(config.API + config.API.PLAYERSLEADERBOARD, {
    params: {
        splits: self.splits,
        playingPosition: self.playingPosition,
        competitionId: self.competitionId,
        page: self.pagination,
        sort: self.sort,
        order: self.order,
        limit: self.limit,
    }
}).then( (response) => {
    let data = response.data.data;
    let lastpage = response.data.last_page;

    if ( data.length ) {
        self.leagueLeaders = self.leagueLeaders.concat(data);
        self.$refs.infiniteLoading.$emit('$InfiniteLoading:loaded');
        self.pagination += 1;
        if(self.pagination == lastpage){
            self.$refs.infiniteLoading.$emit('$InfiniteLoading:complete');
            console.log(123);
        }
    }
    else {
        self.$refs.infiniteLoading.$emit('$InfiniteLoading:complete');
        if( url.includes('orderby') ) {
            let order = url.split('/').pop();
            let highlight = document.getElementsByClassName(order);
            _.forEach(highlight, (elem, key) => {
                elem.className += ' hightlight';
            });
        }
        else {
            let highlight = document.getElementsByClassName('points');
            _.forEach(highlight, (elem, key) => {
                elem.className += ' hightlight';
            });
        }
    }
});

@rodwin
Copy link

rodwin commented Jul 5, 2017

I am also experiencing this issue. The event keeps on firing even if I am not scrolling. Its weird because I just followed the guide. I am using elementUI's table

@PeachScript
Copy link
Owner

PeachScript commented Jul 5, 2017

@PenAndPapers @rodwin which version of Vue.js and this component do you use? If it is possible, please reproduce your problem on JSFiddle, thanks!

@PenAndPapers
Copy link

I'm using "vue": "^2.0.1" and "axios": "^0.15.2".

@PenAndPapers
Copy link

I thought it was not compatible with axios so I tried to use "vue-resource": "^1.2.1", but still no luck

@PeachScript
Copy link
Owner

@PenAndPapers I think it was not caused by ajax lib, if you are using vue-router and enable the keep-alive feature, I recommend you to try to use the Vue.js v2.2.0 and later, refer issue.

@mcmillion
Copy link

I'm seeing this issue as well with VueJS 2.3.4. I'm also seeing it send out two events each time.

@PenAndPapers
Copy link

@PeachScript I've tried Vue.js v2.2.6 still not working, im not using vue router on my project

@PeachScript
Copy link
Owner

@mcmillion @PenAndPapers I need your help to find the real reason, could you reproduce this problem on JSFiddle? You can use setTimeout instead of ajax requests, thanks!

@vbabenko
Copy link

vbabenko commented Jul 10, 2017

I have same issue (Vue 2.3) and vue-infinite-loading (2.1.3) sends event all time. Similar case to @DaveSanders.
I tried to create jsFiddle but I could not reproduce https://jsfiddle.net/vbabenko/fb6r82eb/3/ even with flexbox. It's pretty hard to move part of project to jsfiddle for reproducing...

@PeachScript Could the issue be related to css?

@DaveSanders
Copy link
Author

To make matters worse (at least for finding the bug) its stopped doing it for me, and seems to be working fine now. I'm really not sure what I've changed. I'm guessing its related to page structure, and I did move some things around when we redesigned the screen. I was going to go back to look at old commits to see if I can find the difference, but I've been slammed with crunch time here.

@vbabenko
Copy link

@DaveSanders
yeah, it's my assumption too, I am using vue-infinite-loading on several projects and only one has such behavior. Looks like it sensitive to html/css structure.

@adamyarger
Copy link

@DaveSanders Ive run into the same problem when I nest 'infinite-loading' in divs while using window as the scroll parent. What I've noticed in the infiniteLoading.vue file is that the getCurrentDistance function does not account for the infinite-loading component to be further down the page then it is.

When i change the function to the following everything is resolved.

  function getCurrentDistance(elm, dir) {
    let distance;
    const scrollTop = isNaN(elm.scrollTop) ? elm.pageYOffset : elm.scrollTop;
    if (dir === 'top') {
      distance = scrollTop;
    } else {
      let scrollElmHeight;
      if (elm === window) {
        scrollElmHeight = window.innerHeight;
        distance = this.$el.getBoundingClientRect().top - scrollTop - scrollElmHeight - (elm.offsetTop || 0);
      } else {
        scrollElmHeight = elm.getBoundingClientRect().height;
        distance = this.$el.offsetTop - scrollTop - scrollElmHeight - (elm.offsetTop || 0);
      }
    }
    return distance;
  }

@PeachScript
Copy link
Owner

@vbabenko I'm not sure how this issue is caused, maybe related to CSS/HTML. The tricky place is, we have no way to reproduce it, so it is difficult to find the real reason...

@PeachScript
Copy link
Owner

@DaveSanders waiting for your good news, thank you very much!

@PeachScript
Copy link
Owner

@vbabenko is there has some specials in your problem project? Such as the different scroll container, the different front-end router, the different nested HTML structure, etc.

@duyhung85
Copy link

duyhung85 commented Jul 11, 2017

I'm having this issue again today too. In my case I think its because the component that have infiniteLoading init and running is hidden and it keeps loading till I open it.
Here is my setup: I have a toolbar tab component (using Bootstrap for HTML&CSS):

<div class="toolbar-content nano">
            <div class="tab-content nano-content" id="toolbar-tab">
                <tab-layout></tab-layout>
                <tab-bkgrnd></tab-bkgrnd>           
                </div>
            </div>
        </div>

The tab-bkgrnd component is hidden by default and that is where I have infiniteLoading setup and running. When I first access the page infiniteLoading keeps loading forever until I click on tab-bkgrnd. If I change tab-bkgrnd to open by default then its only load once and working as expected when scrolling down.

@PeachScript
Copy link
Owner

@duyhung85 yep, because the getBoundingClientRect method will all return 0 if the element was hidden, so this plugin cannot calculate correct distance if it was hidden, perhaps you can try v-if to solve it.

@vbabenko
Copy link

vbabenko commented Jul 11, 2017

@PeachScript I think the issue appear when styles wrote in bad manner, like this
https://jsfiddle.net/vbabenko/fb6r82eb/7/

css class 'top' has overflow-x: hidden
css class 'deploy' has overflow: auto

in this case it will invoke function to the end while data exists. (open console to see invocation)

when you comment overflow: auto in last class - everything will work.

Maybe it can help.

When I have time I will try debug source file to be sure on 100%

@PeachScript
Copy link
Owner

@vbabenko it's a very useful information, thank you very much!

@PeachScript
Copy link
Owner

@DaveSanders @PenAndPapers @rodwin @vbabenko @adamyarger @mcmillion hi everyone, sorry to bother, could you tell me does your scroll container has a fixed height?

@vbabenko
Copy link

@PeachScript, it's okay, thank you for your library, it's awesome.

In my case - no (everything positioning by flexbox), my scroll container has flex-grow: 1; overflow: auto;

@adamyarger
Copy link

@PeachScript, no im using the window to scroll. I believe i may have been using an older version of the component before when when offsetTop was being used to measure the distance, it now looks like getBoundingClientRect().top is being used. So everything works as expected now.

@PeachScript
Copy link
Owner

@vbabenko thanks for your appreciation! This plugin will calculate distance through the getBoundingClientRect().top of infinite-loading element and the getBoundingClientRect().bottom of scroll container, the distance is expected when the top - bottom <= the passing distance, but if the scroll container has automatic height, the distance will always be expected...

So I think should to add a additional condition to process it, I will as soon as possible.

@PeachScript
Copy link
Owner

@adamyarger got it, thanks for your feedback!

Best regards.

@PeachScript
Copy link
Owner

@vbabenko @Akari1987 I have encountered a thorny problem. For now, this plugin will find the closest parent node that has overflow-y: auto CSS style as the scroll container, but in the example that provided by @vbabenko , the closest overflow-y: auto parent node is not the real scroll container, so I have planed to check the height property at the same time, if the element has overflow-y: auto, and it's height property not be auto or it's max-height property not be none, auto or 0px, it should be the real scroll container. The problem is, I did not found a better way to detect whether a element's height property is auto, do you have any idea?

@PeachScript
Copy link
Owner

@Akari1987 thanks, waiting for your good news!

@PeachScript
Copy link
Owner

Hi all participants @DaveSanders @Akari1987 @PenAndPapers @rodwin @mcmillion @vbabenko @adamyarger @duyhung85 , I have no idea about how to find the real scroll parent, but this issue has been created for 2 months, so I plan to add a special property to solve it, looks like this:

<div infinite-wrapper>
  <div style="overflow: auto;">
    <infinite-loading force-use-infinite-wrapper="true"></infinite-loading>
  </div>
</div>

The special property called force-use-infinite-wrapper, it will find the closest parent node which has infinite-wrapper attribute, and it will ignore other parent node, even if some parents has overflow-y: auto|scroll CSS styles.

What do you think about the solution? And how about the attribute name force-use-infinite-wrapper?

Best regards.

@vbabenko
Copy link

Sounds good. It would be nice to update documentation, this property is not obvious for those who doesn't aware about this issue

@PeachScript
Copy link
Owner

@vbabenko perhaps we can observe the number of times when this component be trigger, and we can throw a warning if it was triggered many times in a short time, do you think it is feasible?

@PeachScript PeachScript added the bug label Sep 5, 2017
@JefferyHus
Copy link

I dunno but I have been testing around, what i have noticed is that first you have to set the height of your body to auto then this listen will do a great work:

window.onscroll = function(ev) {
    if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
        // scroll hits the floor, then you can call the function
    }
};

@PeachScript
Copy link
Owner

PeachScript commented Sep 8, 2017

@JefferyHus Sorry, I don't know what do you want to solve...Is your solution related to this issue?

@JefferyHus
Copy link

yes it is, when ever I scroll down once the loading never stops and keeps calling my function to the infinite, so I had to change the function on the scroll listener and it worked now.

@PeachScript
Copy link
Owner

@JefferyHus thanks for your reply! Perhaps there are many reasons for this issue, I need your help, could you reproduce your problem on JSFiddle?

@JefferyHus
Copy link

@PeachScript emmm, I will try even tho im not sure if it will reproduce again but will also put the solution I did, once im free

@PeachScript
Copy link
Owner

PeachScript commented Sep 15, 2017

Hi everyone, v2.2.0 has been released, include the force-use-infinite-wrapper feature, you can try it now, please feedback to here if you find any problem, thanks :D

@junpls
Copy link

junpls commented Oct 8, 2017

@PeachScript thanks a lot for force-use-infinite-wrapper! My current problem with it though is that I cannot chance this property during runtime. I have a responsive design in which I only want this behavior in portrait mode. What I'm trying is :force-use-infinite-wrapper="!landscape"

@PeachScript
Copy link
Owner

@junpls this component will only search scroll wrapper when it is initialized, what is the situation that you need to change scroll wrapper during runtime?

@junpls
Copy link

junpls commented Oct 9, 2017

@PeachScript this is what I'm trying:
(It should say "infinite" on the left side as well)
ab2e398604bab119

@PeachScript
Copy link
Owner

@junpls I see, thanks for your explanation, I will add responsive support the force-use-infinite-wrapper property in the next version.

@lautiamkok
Copy link

lautiamkok commented Aug 22, 2018

This works for me:

mounted() {
       window.addEventListener('scroll',this.onscroll)
 },
onscroll: async function (event) {
      const scrollY = window.scrollY
      const visible = document.documentElement.clientHeight
      const pageHeight = document.documentElement.scrollHeight
      const bottomOfPage = visible + scrollY >= pageHeight

      if (bottomOfPage || pageHeight < visible) {
            this.fetchPosts()
           console.log('At the bottom');
      }
},

Ref: https://scotch.io/tutorials/simple-asynchronous-infinite-scroll-with-vue-watchers

@yasin7044
Copy link

v2.1.3 - for some reason the "loaded" emit isn't stopping it from continuing to load results down the page. I'm pretty sure this was working before, but I can't figure out why this is happening.

So, basically even though I haven't scrolled down, it keeps hitting my server and loading more results. Here's my onInfinite function:

onInfinite () {
        api.tracks.get(PAGE_AMOUNT, this.tracks.length, tr => {
          console.log(`TRACKS: ${this.tracks.length}`)

          if (tr.length > 0) {
            this.tracks = this.tracks.concat(tr)
            if (tr.length < PAGE_AMOUNT) {
              this.$refs.infiniteLoading.$emit('$InfiniteLoading:complete')
            } else {
              this.$refs.infiniteLoading.$emit('$InfiniteLoading:loaded')
            }
          } else {
            this.$refs.infiniteLoading.$emit('$InfiniteLoading:complete')
          }
        })
      }

My template:

<template>
  <div id="track-list">
    <TrackItem v-for='(track, index) in tracks' :track='track' :index="index" :key='track.id'/>
    <infinite-loading :on-infinite="onInfinite" ref="infiniteLoading" spinner="waveDots"></infinite-loading>
  </div>
</template>

I did put console logs in and it IS hitting that else where it sends the loaded emit. I also changed it to :complete and it stopped calling at that point in the code. So it is emitting, it just seems like its not caring - or for some reason it thinks that its scrolled down.

Anything I'm doing wrong? Or any ideas on how to debug it further?

please add
infinite-wrapper attriubte
and :force-use-infinite-wrapper="true"
<infinite-loading
@infinite="infiniteHandler"
:identifier="indetifyId"
:force-use-infinite-wrapper="true"
spinner="circles">

<TrackItem v-for='(track, index) in tracks' :track='track' :index="index" :key='track.id'

infinite-wrapper
/>

@greetfish
Copy link

greetfish commented Jun 23, 2021

I also experiencing this issue, but not about CSS/html ,it was coursed by the array increase method, when i increase array like this
Array.prototype.push.apply(this.infiniteArticles.content, newArticles.content)
i get uncontrol infinite loading, and it work well like this
this.infiniteArticles.content = this.infiniteArticles.content.concat(newArticles.content)

@trandaison
Copy link

trandaison commented Aug 25, 2021

There will be one more case that causes calling handler multiple time.

Here is my handler. I've added a filter statement to make sure there are no duplicated records.

infiniteHandler($state) {
  axios.get(api, {
    params: {
      page: this.page,
    },
  }).then(({ data }) => {
    if (data.hits.length) {
      this.page += 1;
      const newHits = data.hits.filter((hit) => 
        this.list.every((item) => item.id !== hit.id)
      );
      this.list.push(...newHits);
      $state.loaded();
    } else {
      $state.complete();
    }
  });
}

The problem comes when the data.hits.length > 0 and newHits = [], so the list never changes and it keeps calling the handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests