Files
materio-d9/web/themes/custom/materiotheme/vuejs/components/Pages/Base.vue
bach 2f5a230370 SearchForm: fix inconsistent/mixed search results
- SearchForm.vue: route Enter key through submit() (native form submit
  interception) so it behaves like the button; fix autocomplete array
  mutation during iteration in the typed watcher.
- Base.vue: parse terms consistently in beforeRouteUpdate; render items
  via displayedItems (drops sparse holes); only mount infinite-loading
  after the first page and reset it per search via :identifier.
- search store: guard against stale async responses (searchId); place
  each page at its offset instead of concatenating in arrival order,
  which mixed pages when a later page resolved first.
2026-07-15 21:11:53 +02:00

144 lines
4.3 KiB
Vue

<template>
<div id="Base">
<div class="loading" v-if="!searchinfos">
<span>{{ $t('default.Loading…') }}</span>
</div>
<div class="cards-list" v-else>
<aside class="search-info">
{{ searchinfos }}
</aside>
<div class="loading" v-if="!items.length & !noresults">
<span>{{ $t('default.Loading…') }}</span>
</div>
<ul v-else>
<li v-for="item in displayedItems" v-bind:key="item.id">
<Card v-if="item.bundle == 'materiau'" :item="item"/>
<CardThematique v-if="item.bundle == 'thematique'" :item="item"/>
</li>
</ul>
<infinite-loading
v-if="count > limit && displayedItems.length >= limit"
:identifier="searchId"
@infinite="nextPage"
>
<div slot="no-more">No more results</div>
</infinite-loading>
</div>
</div>
</template>
<script>
import Card from 'vuejs/components/Content/Card'
import CardThematique from 'vuejs/components/Content/CardThematique'
import { mapState, mapActions } from 'vuex'
export default {
name: "Base",
data() {
return {
pagetitle:"Base",
// searchinfos: null
}
},
computed: {
...mapState({
items: state => state.Search.items,
searchinfos: state => state.Search.infos,
count: state => state.Search.count,
noresults: state => state.Search.noresults,
limit: state => state.Search.limit,
searchId: state => state.Search.searchId
}),
// items is a sparse array (pages placed by offset); drop the holes left by
// pages that returned fewer results than the limit before rendering.
displayedItems () {
return this.items.filter(Boolean)
}
},
methods: {
...mapActions({
newSearch: 'Search/newSearch',
nextPage: 'Search/nextPage'
}),
// infiniteHandler($state){
// console.log('inifiniteHandler', $state)
// this.nextPage()
// }
},
created() {
// at first page load or first route entering launch a search if params exists in url query
console.log('Base created() location',window.location)
let params = new URLSearchParams(window.location.search)
if (params.has('keys')) {
const r = /,\s?$/
let keys = params.get('keys').replace(r,'').split(', ')
console.log('Base created, keys', keys)
this.$store.commit('Search/setKeys', keys)
this.pagetitle = keys.join(', ') //params.get('keys')
} else {
this.$store.commit('Search/reSetKeys')
this.pagetitle = 'Base'
}
if (params.has('terms')) {
console.log('Base created, has terms', params.get('terms'))
// this.$store.commit('Search/setTerms', params.get('terms').split(','))
this.$store.commit('Search/setTerms', JSON.parse(params.get('terms')))
} else {
this.$store.commit('Search/reSetTerms')
}
if (params.has('filters')) {
this.$store.commit('Search/setFilters', params.get('filters').split(','))
} else {
this.$store.commit('Search/reSetFilters')
}
this.newSearch()
},
beforeRouteUpdate (to, from, next) {
// when query change launch a new search
console.log('Base beforeRouteUpdate', to, from, next)
// todo text field of search form is not emptying on clicking on base after a search
// this.$store.commit('Search/setKeys', to.query.keys)
if (to.query.hasOwnProperty('terms')) {
// to.query.terms is a raw JSON string (see SearchForm.submit) and must be
// parsed like in created(), otherwise getResults() double-encodes it and
// the backend silently drops the terms (less relevant results).
this.$store.commit('Search/setTerms', JSON.parse(to.query.terms))
}else{
this.$store.commit('Search/reSetTerms')
}
if (to.query.hasOwnProperty('filters')) {
this.$store.commit('Search/setFilters', to.query.filters)
}else{
this.$store.commit('Search/reSetFilters')
}
if (to.query.hasOwnProperty('keys')) {
const r = /,\s?$/
let keys = to.query.keys.replace(r,'').split(', ')
console.log('Base created, keys', keys)
this.$store.commit('Search/setKeys', keys)
this.pagetitle = to.query.keys
}else{
this.$store.commit('Search/reSetKeys')
}
this.newSearch()
next()
},
components: {
Card,
CardThematique
}
}
</script>
<style lang="scss" scoped>
</style>