mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-11-16 22:25:30 +08:00
142 lines
4.3 KiB
Vue
142 lines
4.3 KiB
Vue
<template>
|
|
<checklistSelect
|
|
:class="{
|
|
['sn-select sn-select--search hover:border-sn-sleepy-grey']: true,
|
|
'sn-select--open': shouldOpen,
|
|
'sn-select--blank': !valueLabel,
|
|
'disabled': disabled
|
|
}"
|
|
:className="className"
|
|
:optionsClassName="optionsClassName"
|
|
:withButtons="withButtons"
|
|
:withEditCursor="withEditCursor"
|
|
:initialSelectedValues="initialSelectedValues"
|
|
:options="currentOptions"
|
|
:placeholder="placeholder"
|
|
:noOptionsPlaceholder="isLoading || isLazyLoading ? i18n.t('general.loading') : noOptionsPlaceholder"
|
|
:disabled="disabled"
|
|
:shouldOpen="shouldOpen"
|
|
:shouldUpdateWithoutValues="shouldUpdateWithoutValues"
|
|
:shouldUpdateOnToggleClose="shouldUpdateOnToggleClose"
|
|
@reached-end="handleReachedEnd"
|
|
@close="shouldOpen = false"
|
|
@update-selected-values="selectedValues = $event"
|
|
>
|
|
<div class="flex w-full" @click="shouldOpen = !shouldOpen">
|
|
<input
|
|
ref="focusElement"
|
|
v-model="query"
|
|
type="text"
|
|
class="sn-select__search-input"
|
|
:placeholder="placeholder"
|
|
@blur="query = ''" />
|
|
<span class="sn-select__value">{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span>
|
|
<i class="sn-icon" :class="{ 'sn-icon-down': !shouldOpen, 'sn-icon-up': shouldOpen}"></i>
|
|
</div>
|
|
</checklistSelect>
|
|
</template>
|
|
|
|
<script>
|
|
import checklistSelect from './checklist_select.vue';
|
|
import { debounce } from '../debounce';
|
|
|
|
export default {
|
|
name: 'ChecklistSearch',
|
|
props: {
|
|
withButtons: { type: Boolean, default: false },
|
|
withEditCursor: { type: Boolean, default: false },
|
|
initialSelectedValues: { type: Array, default: () => [] },
|
|
options: { type: Array, default: () => [] },
|
|
placeholder: { type: String },
|
|
noOptionsPlaceholder: { type: String },
|
|
disabled: { type: Boolean, default: false },
|
|
className: { type: String, default: '' },
|
|
optionsClassName: { type: String, default: '' },
|
|
shouldUpdateWithoutValues: { type: Boolean, default: false },
|
|
shouldUpdateOnToggleClose: { type: Boolean, default: false },
|
|
isLoading: { type: Boolean, default: false },
|
|
params: { type: Array, default: () => [] },
|
|
optionsUrl: { type: String, required: true },
|
|
lazyLoadEnabled: { type: Boolean, default: false }
|
|
},
|
|
components: { checklistSelect },
|
|
emits: ['reached-end', 'update-options'],
|
|
data() {
|
|
return {
|
|
query: null,
|
|
currentOptions: null,
|
|
shouldOpen: false,
|
|
nextPage: 1,
|
|
isLazyLoading: false,
|
|
selectedValues: []
|
|
};
|
|
},
|
|
created() {
|
|
this.currentOptions = this.options;
|
|
},
|
|
watch: {
|
|
query() {
|
|
if (!this.query) {
|
|
this.currentOptions = this.options;
|
|
return;
|
|
}
|
|
|
|
if (this.optionsUrl) {
|
|
// reset current options and next page when lazy loading is enabled
|
|
if (this.lazyLoadEnabled) {
|
|
this.currentOptions = [];
|
|
this.isLazyLoading = true;
|
|
this.nextPage = 1;
|
|
}
|
|
this.$nextTick(() => {
|
|
debounce(this.fetchOptions(), 10);
|
|
});
|
|
} else {
|
|
this.currentOptions = this.options.filter((o) => o[1].toLowerCase().includes(this.query.toLowerCase()));
|
|
}
|
|
},
|
|
options() {
|
|
this.currentOptions = this.options;
|
|
}
|
|
},
|
|
computed: {
|
|
valueLabel() {
|
|
if (!this.selectedValues.length) return '';
|
|
if (this.selectedValues.length === 1) {
|
|
return this.currentOptions.find(({ id }) => id === this.selectedValues[0])?.label;
|
|
}
|
|
return `${this.selectedValues.length} ${this.i18n.t('general.options_selected')}`;
|
|
}
|
|
},
|
|
methods: {
|
|
handleReachedEnd() {
|
|
if (this.query) {
|
|
this.fetchOptions();
|
|
} else {
|
|
this.$emit('reached-end');
|
|
}
|
|
},
|
|
fetchOptions() {
|
|
if (!this.nextPage || !this.optionsUrl) return;
|
|
|
|
$.ajax({
|
|
url: this.optionsUrl,
|
|
data: {
|
|
...(this.query && { query: this.query }),
|
|
...(this.lazyLoadEnabled && this.nextPage && { page: this.nextPage }),
|
|
...this.params
|
|
},
|
|
success: (result) => {
|
|
if (this.lazyLoadEnabled) {
|
|
this.nextPage = result.next_page;
|
|
this.$emit('update-options', this.currentOptions, result);
|
|
this.isLazyLoading = false;
|
|
return;
|
|
}
|
|
this.currentOptions = result;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
</script>
|