metafizzy / infinite-scroll

📜 Automatically add next page
https://infinite-scroll.com
7.41k stars 1.74k forks source link

Plugin instance is ignoring new path function set with InfiniteScroll.prototype.option method #936

Open luxplanjay opened 3 years ago

luxplanjay commented 3 years ago

What it says in the description. My case is a form where a user can enter a search term for an api request. Every new form submission I need to reset path option to generate proper URL with query param.

Made a simple live example where after infScroll.option({path() {}}) the instance is still using the path function that it was initialized with. Here's a link to CodePen.

PS: Under the hood option method is using Object.assign and it actually works fine with other options, but for some reason ignores new path function.

PSS: Perhaps I'm supposed to destroy and reinitialize a new instance on every form submission?

desandro commented 3 years ago

Thanks for reporting this issue! You are correct, the path behavior will not be changed after you re-set path. You actually need to trigger an undocumented method updateGetPath to have your change take effect. That's the technical solution

// set new path option
infScroll.option.path = 'new path';
// update behavior
infScroll.updateGetPath();

Since your demo is already using a function, another solution is to update variables used within the function, so the same function could be used. See CodePen

luxplanjay commented 3 years ago

Since your demo is already using a function, another solution is to update variables used within the function, so the same function could be used. See CodePen

So what you are saying is I basically need a global variable, which will work in this case for sure. But what if instance initialization is done in a separate file inside a function where I have no way to access anything global. I can «hack» it with object reference and а function that accepts options object.

// this lives in some initscroll.js
export default function initiInfScroll(options) {
  return new InfiniteScroll(".js-container", {
    path() {
      return options.pathUrl;
    }
  });
}

// app.js
import initiInfScroll from 'path/to/initscroll';

const infScrollOptions = {
  pathUrl: 'https://jsonplaceholder.typicode.com/todos/1'
}
const infScroll = initiInfScroll(infScrollOptions);

document.querySelector(".js-change-path-btn").addEventListener("click", () => {
  infScrollOptions.pathUrl = "https://jsonplaceholder.typicode.com/todos/2";
});

But this just feels so wrong. Mutating cross-module object reference is not exactly safe.

Actually doing some monkey patching feels better and kinda ok, given the situation.

// Adding pathUrl field to this instance, so there will be no prototype pollution
// and then using it on the instance
const instance = new InfiniteScroll(".js-container", {
    path() {
      return this.pathUrl ?? '/1'
    },
})

// And then just change it when needed
instance.pathUrl = '/2'

Are there any plans in the API to support this case (which is very common to be honest) or monkey patching is the way?

desandro commented 3 years ago

But what if instance initialization is done in a separate file inside a function where I have no way to access anything global.

In this case, I recommend you trigger updateGetPath after setting a new path.

luxplanjay commented 3 years ago

In this case, I recommend you trigger updateGetPath after setting a new path.

Will try and get back to you with results.

Erwane commented 3 years ago

Hi. Got same issue, and add another problem about currentIndex

My index have form, loading content thrue Ajax. I update path like this :

        $(document).on('loaded.index.app', (event, body) => {
            if (body.path) {
                console.log("new path=" + body.path);
                this.infinite.options.path = body.path;
                this.infinite.updateGetPath();
            }
        })

Here the process

first load, Initialize infinite-scroll

optPath=/fr/bands/France.json?page={{#}}; nextIndex=2
core.js:207 optPath=/fr/bands/France.json?page={{#}}; nextIndex=2
core.js:153 [InfiniteScroll] initialized. on card-index bands

Add ar in query search and press button.

infinite.js:23 new path=/fr/bands/France.json?q=ar&page={{#}}

Scroll down

core.js:153 [InfiniteScroll] scrollThreshold
core.js:207 optPath=/fr/bands/France.json?page={{#}}; nextIndex=2
core.js:153 [InfiniteScroll] request. URL: /fr/bands/France.json?page=2
core.js:153 [InfiniteScroll] load. Annuaire des groupes - France. URL: /fr/bands/France.json?page=2

Scroll up, change query search to b Setting new path

infinite.js:23 new path=/fr/bands/France.json?q=b&page={{#}}
core.js:153 [InfiniteScroll] scrollThreshold
core.js:207 optPath=/fr/bands/France.json?page={{#}}; nextIndex=3
core.js:153 [InfiniteScroll] request. URL: /fr/bands/France.json?page=3
core.js:153 [InfiniteScroll] load. Annuaire des groupes - France. URL: /fr/bands/France.json?page=3

getPath and index are not reset. Maybe a reset() method would be cool ?