<template> <Context :class="{ 'context--loading-overlay': view._.loading }" :overflow-scroll="true" :max-height-if-outside-viewport="true" @shown="focus" > <form class="context__form" @submit.prevent="searchIfChanged"> <div class="control margin-bottom-1"> <div class="control__elements"> <div class="input__with-icon input__with-icon--left" :class="{ 'input__with-icon--loading': loading }" > <input ref="activeSearchTermInput" v-model="activeSearchTerm" type="text" :placeholder="$t('viewSearchContext.searchInRows')" class="input" @keyup="searchIfChanged" /> <i class="iconoir-search"></i> </div> </div> </div> <div v-if="!alwaysHideRowsNotMatchingSearch" class="control control--align-right margin-bottom-0" > <SwitchInput v-model="hideRowsNotMatchingSearch" @input="searchIfChanged" > {{ $t('viewSearchContext.hideNotMatching') }} </SwitchInput> </div> </form> </Context> </template> <script> import debounce from 'lodash/debounce' import context from '@baserow/modules/core/mixins/context' export default { name: 'ViewSearchContext', mixins: [context], props: { view: { type: Object, required: true, }, fields: { type: Array, required: true, }, storePrefix: { type: String, required: true, }, alwaysHideRowsNotMatchingSearch: { type: Boolean, required: false, default: false, }, }, data() { return { activeSearchTerm: '', lastSearch: '', hideRowsNotMatchingSearch: true, lastHide: true, loading: false, } }, methods: { focus() { this.$nextTick(function () { this.$refs.activeSearchTermInput.focus() }) }, searchIfChanged() { this.$emit('search-changed', this.activeSearchTerm) if ( this.lastSearch === this.activeSearchTerm && this.lastHide === this.hideRowsNotMatchingSearch ) { return } this.search() this.lastSearch = this.activeSearchTerm this.lastHide = this.hideRowsNotMatchingSearch }, search() { this.loading = true // When the user toggles from hiding rows to not hiding rows we still // need to refresh as we need to fetch the un-searched rows from the server first. if (this.hideRowsNotMatchingSearch || this.lastHide) { // noinspection JSValidateTypes this.debouncedServerSearchRefresh() } else { // noinspection JSValidateTypes this.debouncedClientSideSearchRefresh() } }, debouncedServerSearchRefresh: debounce(async function () { await this.$store.dispatch( `${this.storePrefix}view/${this.view.type}/updateSearch`, { activeSearchTerm: this.activeSearchTerm, hideRowsNotMatchingSearch: this.hideRowsNotMatchingSearch, // The refresh event we fire below will cause the table to refresh it state from // the server using the newly set search terms. refreshMatchesOnClient: false, fields: this.fields, } ) this.$emit('refresh', { callback: this.finishedLoading, }) }, 400), // Debounce even the client side only refreshes as otherwise spamming the keyboard // can cause many refreshes to queue up quickly bogging down the UI. debouncedClientSideSearchRefresh: debounce(async function () { await this.$store.dispatch( `${this.storePrefix}view/${this.view.type}/updateSearch`, { activeSearchTerm: this.activeSearchTerm, hideRowsNotMatchingSearch: this.hideRowsNotMatchingSearch, refreshMatchesOnClient: true, fields: this.fields, } ) this.finishedLoading() }, 10), finishedLoading() { this.loading = false }, }, } </script>