rocwang/vue-virtual-scroll-grid

[Help] Filter Grid list

lannodev opened this issue · 3 comments

Hi, I'm trying to filter my grid list using an array object but the list doesn't update

const filteredSongs = computed(() => {
  if (searchTerm.value == '') return library.songs;
  return library.songs.filter((song) => {
    return (
      song.title.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
      song.name.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
      song.artist?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase())
    );
  });
});

async function pageProvider(pageNumber: number, pageSize: number) {
  if (pageNumber == 0) pageNumber = 1;
  let songs = filteredSongs.value.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
  return songs;
}

Please could you give me an example like this ?
https://codesandbox.io/s/vue-virtual-scroll-grid-esm-vt27c?file=/App.vue

The component only refreshes itself when the input props change.

You may try converting your pageProvider into a computed value, i.e. a function factory that computes a new pageProvider when your search term changes.

Something like:

const computedPageProvider = computed(() => {
	return async function pageProvider(pageNumber: number, pageSize: number) {
	  if (pageNumber == 0) pageNumber = 1;
	  let songs = filteredSongs.value.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
	  return songs;
	}
})

Did not work :(
To resolve I had to add a key property:

<Grid
        :length="filteredSongs.length"
        :respectScrollToOnResize="true"
        :pageSize="12"
        :pageProviderDebounceTime="0"
        :pageProvider="pageProvider"
        :key="componentKey"
        class="3xl: grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:md:grid-cols-4 xl:md:grid-cols-5 2xl:md:grid-cols-6">
        <template v-slot:probe>
          <MusicCard />
        </template>
...
const filteredSongs = computed(() => {
  componentKey.value += 1; //here
  if (searchTerm.value == '') return library.songs;

The component only refreshes itself when the input props change.

You may try converting your pageProvider into a computed value, i.e. a function factory that computes a new pageProvider when your search term changes.

Something like:

const computedPageProvider = computed(() => {
	return async function pageProvider(pageNumber: number, pageSize: number) {
	  if (pageNumber == 0) pageNumber = 1;
	  let songs = filteredSongs.value.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
	  return songs;
	}
})

This doesn't work is because filteredSongs is accessed only in the returned async function, so computed doesn't count it as a dependency. Instead, it needs to be accessed in the function passed to computed directly, like:

const computedPageProvider = computed(() => {
	const filtered = filteredSongs.value
	return async function pageProvider(pageNumber: number, pageSize: number) {
	  if (pageNumber == 0) pageNumber = 1;
	  let songs = filtered.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
	  return songs;
	}
})

Compared to the solution of updating key whenever filtered items change, this has the advantage that the entire grid does not get recreated so there is no noticeable screen flashing.