Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dcranmer's avatar

Delay/bypass watchers when clearing filters (Laravel/Inertia/Vue 3)

In a Laravel/Inertia/Vue 3 app, I have a Vue component (a search-and-filtered-results page) with several filters (checkboxes, selects, text search). I set up one watcher for the text search that uses debounce() to build in a slight delay. I set up a single, second watcher for the other filters that normally don't need a delay. The watchers send a Get request to Laravel when any of the relevant data properties changes. This works fine...except that now I also have a button that clears all of the filters. Now the data that gets returned by inertia is incorrect -- it seems as though I need to delay the watcher trigger until all of the data properties are cleared. I'm also not sure whether it's necessary to send multiple Get requests when the filters are cleared. It seems as though I need to delay the watcher trigger until all of the filter data properties are cleared. It also seems as though a single Get request -- just in this case -- would be optimal. Or is there some way to bypass the watchers altogether?

<script setup>

const search = ref(props.filters.search || '')
const county = ref(props.filters.county || '')
const school = ref(props.filters.school || '')
const areas = ref(props.filters.areas || [])

watch(search, debounce(() => {
  router.get(route('project.search-advanced', {
    search: search.value,
    county: county.value,
    school: school.value,
    areas: areas.value,
    preserveState: true,
    replace: true
  }))
}, 500))
watch([county, school, areas], () => {
  router.get(route('project.search-advanced', {
    search: search.value,
    county: county.value,
    school: school.value,
    areas: areas.value,
    preserveState: true,
    replace: true
  })
  )
})

const clearFilters =  () => {
// something like this 
search.value = ''
 county.value = ''
 school.value = ''
 areas.value.length = 0
}
</script>

<template>
     <button
        type="button"
        @click="clearFilters"
       >
        Clear filters
      </button>

[pseudo code for filters]

Text Search
  <input
    type="search"
    name="search"
     v-model="search"
    >

County
   <select
     v-model="county"
      name="county"
     >
<option v-for="county of counties" :value="county.id">

[same for schools]


Areas (v-for loop)
 <input
    type="checkbox"
     v-model="areas"
      :value="area.id"
   >

</template>
0 likes
10 replies
LaryAI's avatar
Level 58

To bypass the watchers altogether, you can use watchEffect instead of watch. watchEffect will automatically run the function when any reactive property it depends on changes. You can also use a ref to keep track of whether the filters have been cleared or not. Here's an example:

<script setup>
import { ref, watchEffect } from 'vue'

const search = ref(props.filters.search || '')
const county = ref(props.filters.county || '')
const school = ref(props.filters.school || '')
const areas = ref(props.filters.areas || [])
const filtersCleared = ref(false)

watchEffect(() => {
  if (!filtersCleared.value) {
    router.get(route('project.search-advanced', {
      search: search.value,
      county: county.value,
      school: school.value,
      areas: areas.value,
      preserveState: true,
      replace: true
    }))
  }
})

const clearFilters = () => {
  filtersCleared.value = true
  search.value = ''
  county.value = ''
  school.value = ''
  areas.value.length = 0
  filtersCleared.value = false
}
</script>

In this example, we use watchEffect to automatically trigger the router.get function whenever any of the reactive properties change. We also use a ref called filtersCleared to keep track of whether the filters have been cleared or not. When the clearFilters function is called, we set filtersCleared to true, clear the filter values, and then set filtersCleared back to false. This ensures that the watchEffect function doesn't trigger while the filters are being cleared.

dcranmer's avatar

Calling a human (or anyone else) please. If I do what the AI says, that watchEffect will start running in an endless loop when the page loads. My requirements are:

  1. except for when filters are being cleared, each filter needs to send a Get request when the relevant data property is changed;

  2. the search filter (text input) is unique because it needs to be delayed slightly (with debounce) to throttle requests

  3. when the clearFilters button is clicked, all filters must be reset to empty, and (hopefully? preferably?) a single Get request is sent to the server -- reloading the initial list is searchable items.

dcx's avatar

@pweil If i understand the problem correctly i think you're almost there with this

const clearFilters =  () => {
// something like this 
search.value = ''
 county.value = ''
 school.value = ''
 areas.value.length = 0
}

you just need to add router.get(route('project.search-advanced'))' to the end of that function..

dcx's avatar

In addition i don't think you even need to reset the refs in that clearFilters method just hit the route and you'll get a fresh dataset I think, if you don't then add preserveState = false

1 like
dcranmer's avatar

@dcx Agree about resetting the refs. I'm still a little uncertain about preserveState, though. I think that I need to keep it; otherwise, the content of the text search box will get cleared out (I think) with each request. At least that's what Jeff says in his Inertia filters lesson.

dcx's avatar

@pweil Yes so you should keep it on the watchers I'm talking about when you want to clear the filters... preserveState should be false...but as per last comment really if you just re hit the original page then it should render from the controller again with no filters..

dcranmer's avatar

@dcx yes, I think that's the ticket. Thanks!

I think I was getting an endless watchEffect loop because I was calling route.get(), which must set some internal refs or something, creating more tracked dependencies. Or something like that. Anyway, I've redone clearFilters() along the lines of your suggestion, with a couple of tweals; e.g., not changing the data properties directly (not necessary) and resetting the clearingFilters ref once the Get request is successful. I also added conditions to the two watchers.

const clearFilters = () => {
  clearingFilters.value = true
  router.get(route('project.search-advanced', {
    search: '',
    county: '',
    school: '',
    areas: [],
    preserveState: true,
    replace: true
  }, {
    onSuccess: () => {
      !clearingFilters.value
    }
  }))
}

watch(search, () => {
  if(!clearingFilters.value) {
  debounce(() => {
    router.get(route('project.search-advanced', {
      search: search.value,
      county: county.value,
      school: school.value,
      areas: areas.value
    preserveState: true,
    replace: true
    }))
  }, 500)
}}
)
watch([county, school, areas], () => {
  if (!clearingFilters.value) {
  router.get(route('project.search-advanced', {
    search: search.value,
    county: county.value,
    school: school.value,
    areas: areas.value,
    preserveState: true,
    replace: true
  })
  )
}})

1 like
dcx's avatar

@pweil I'm glad you got it to work but really when the user first opens the page there is no filters I'm guessing? so really i mean looking at what's here it would work but just hitting the same route the user used to get to the page route with preserveState: false (and no other parameters) and it should also clear - your essentially just refreshing the page data.

But hey...if the above is working then all good :)

dcranmer's avatar

@dcx Of course. :-0 You know, earlier this morning I was just looking at the various route.visit methods in the Inertia docs. At first I thought (wrongly) that route.reload would do what you're talking about, but that preserves the state. So I went back to what I posted above. But your suggestion is much simpler and more straightforward than my solution. Thanks for your help on this! Sometimes I can't see the forest for the trees.

1 like
dcx's avatar

@pweil No problem glad to help, on this "Sometimes I can't see the forest for the trees" this applies to us all on a fairly regular basis I believe, especially when one gets bogged down with a topic.. :)

And yes i agree the Inertia helpers are pretty nice to work with.. especially the form helper in my experience...

Please or to participate in this conversation.