Skip to content

Commit fcfb6fc

Browse files
committed
fix(search) : fix pagination to refresh page result on back and forward button action
1 parent 4dcd8fe commit fcfb6fc

File tree

4 files changed

+79
-40
lines changed

4 files changed

+79
-40
lines changed

components/search/SearchBase.vue

+31-4
Original file line numberDiff line numberDiff line change
@@ -362,11 +362,13 @@ const search = async () => {
362362
*/
363363
const changePage = async (from: number) => {
364364
page.from = from
365-
await search()
365+
// Set loading to true to prevent afterEach router event to trigger a new search
366+
loading.value = true
366367
if (window?.scrollTo) {
367368
window.scrollTo(0, 0)
368369
router.push({ query: { ...route.query, page: from / props.size + 1 } })
369370
}
371+
await search()
370372
}
371373
372374
const { data } = await useAsyncData(async () => {
@@ -390,16 +392,41 @@ watch(
390392
}
391393
)
392394
395+
/**
396+
* Refreshing page result when the user clicks on the “previous page” or “next page” button.
397+
* Listening to the route change and updating the page number accordingly.
398+
*
399+
* This function triggers a new search only if no search is in progress.
400+
* Should be replaced by a better solution when Vue Router will add a Popstate event implementation.
401+
*/
402+
router.afterEach((to, from) => {
403+
// Trigger a new search if the user stay on the same page but URL queries has changed and the search is not in progress
404+
if (to.path == from.path && to.href !== from.href && !loading.value) {
405+
// Get the new page number from the URL query
406+
const from = to.query.page?.toString()
407+
? (parseInt(to.query.page.toString()) - 1) * props.size
408+
: 0
409+
if (from != page.from) {
410+
page.from = from
411+
}
412+
search()
413+
}
414+
})
415+
393416
onMounted(async () => {
394417
await search()
395418
})
396419
397420
// Provide some methods and data to the other components (to be injected)
398421
provide('search', () => {
399-
// Reset the page to 0 when a new search is performed due to a filter change
400-
page.from = 0
401-
search()
422+
if (page.from !== 0) {
423+
// Reset the page to 0 when a new search is performed due to a filter change
424+
changePage(0)
425+
} else {
426+
search()
427+
}
402428
})
429+
403430
provide('declareFilter', declareFilter)
404431
provide(
405432
'response',

components/search/SearchProductCategoryFilter.vue

+4-2
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,17 @@ const selectItem = (value: FacetItem) => {
220220
221221
const setValues = (values: any[]) => {
222222
data.selected = values || []
223-
refreshSearch()
224223
}
225224
226225
if (declareFilter !== null) {
227226
declareFilter({
228227
name: props?.name || '',
229228
title: props.title,
230229
values: data?.selected,
231-
setValues: setValues,
230+
setValues: (values: any[]) => {
231+
data.selected = values || []
232+
refreshSearch()
233+
},
232234
getValuesLabels,
233235
getFilterAggregation,
234236
getQueryAggregation

components/search/SearchRangePrice.vue

+4-2
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,16 @@ export default {
181181
182182
const setValues = (values: any[]) => {
183183
data.selected = values
184-
refreshSearch()
185184
}
186185
if (declareFilter !== null) {
187186
declareFilter({
188187
name: props?.name || '',
189188
title: props.title,
190189
values: data?.selected,
191-
setValues: setValues,
190+
setValues: (values: any[]) => {
191+
data.selected = values || []
192+
refreshSearch()
193+
},
192194
getValuesLabels,
193195
getFilterAggregation,
194196
getQueryAggregation

components/search/SearchTermsAggregation.vue

+40-32
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import {
5252
TermsQuery,
5353
cardinalityAggregation
5454
} from 'elastic-builder'
55-
import { inject, reactive } from 'vue'
55+
import { inject, onMounted, reactive } from 'vue'
5656
import isEqual from '~/utils/IsEqual'
5757
import type { Filter } from './SearchBase.vue'
5858
interface FacetItem {
@@ -121,6 +121,8 @@ export default {
121121
}
122122
},
123123
async setup(props) {
124+
const router = useRouter()
125+
const route = useRoute()
124126
const opened = ref(!props.close)
125127
const sizeQuery = ref(props.size)
126128
const data = reactive({
@@ -182,14 +184,16 @@ export default {
182184
183185
const setValues = (values: any[]) => {
184186
data.selected = values || []
185-
refreshSearch()
186187
}
187188
if (declareFilter !== null) {
188189
declareFilter({
189190
name: props?.name || '',
190191
title: props.title,
191192
values: data?.selected,
192-
setValues: setValues,
193+
setValues: (values: any[]) => {
194+
data.selected = values || []
195+
refreshSearch()
196+
},
193197
getValuesLabels,
194198
getFilterAggregation,
195199
getQueryAggregation
@@ -202,20 +206,18 @@ export default {
202206
203207
const refreshSearch = () => {
204208
if (props.urlParam) {
205-
const $router = useRouter()
206-
const $route = useRoute()
207209
if (data.selected.length > 0) {
208-
$router.push({
210+
router.push({
209211
query: {
210-
...$route.query,
212+
...route.query,
211213
[props.urlParam]: JSON.stringify(data.selected)
212214
}
213215
})
214216
} else {
215-
const query = { ...$route.query }
217+
const query = { ...route.query }
216218
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
217219
delete query[props.urlParam]
218-
$router.push({ query })
220+
router.push({ query })
219221
}
220222
}
221223
if (search !== null) {
@@ -230,6 +232,35 @@ export default {
230232
}
231233
refreshSearch()
232234
}
235+
236+
/**
237+
* Watch the route query for changes and update the selected values if the urlParam is provided
238+
*/
239+
router.afterEach((event) => {
240+
if (props?.urlParam) {
241+
const { query } = event
242+
try {
243+
const values: string[] = JSON.parse((query?.[props?.urlParam] as string) || '[]') || []
244+
const isEqualValues = isEqual(values.sort(), data.selected.sort())
245+
if (!isEqualValues) {
246+
setValues(values)
247+
}
248+
} catch (e) {
249+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
250+
delete query[props?.urlParam]
251+
router.replace({ path: route.path, query })
252+
}
253+
}
254+
})
255+
256+
if (props?.urlParam) {
257+
/**
258+
* Initialize the selected values based on the urlParam provided in props
259+
*/
260+
const query = route.query
261+
const values: string[] = JSON.parse((query?.[props?.urlParam] as string) || '[]') || []
262+
setValues(values)
263+
}
233264
return {
234265
response,
235266
opened,
@@ -241,29 +272,6 @@ export default {
241272
}
242273
},
243274
watch: {
244-
$route: {
245-
handler: function () {
246-
if (!import.meta.env.SSR && this.urlParam) {
247-
const $route = useRoute()
248-
try {
249-
const query: string = ($route.query?.[this.urlParam] as string) || '[]'
250-
const values: string[] = JSON.parse(query) || []
251-
const isEqualValues = isEqual(values.sort(), this.data.selected.sort())
252-
if (!isEqualValues) {
253-
this.setValues(values)
254-
}
255-
} catch (e) {
256-
const $router = useRouter()
257-
const query = { ...$route.query }
258-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
259-
delete query[this.urlParam]
260-
$router.replace({ path: $route.path, query })
261-
}
262-
}
263-
},
264-
immediate: true,
265-
deep: true
266-
},
267275
response: {
268276
handler: function (response) {
269277
if (response?.aggregations) {

0 commit comments

Comments
 (0)