260 lines
7.5 KiB
Vue
260 lines
7.5 KiB
Vue
<template>
|
|
<div class="at-select-wrapper">
|
|
<at-select
|
|
ref="select"
|
|
v-model="model"
|
|
multiple
|
|
filterable
|
|
placeholder=""
|
|
:size="size"
|
|
@click="onClick"
|
|
@input="onChange"
|
|
>
|
|
<li v-if="showSelectAll" class="at-select__option" @click="selectAll()">
|
|
{{ allOptionsSelected ? $t('control.deselect_all') : $t('control.select_all') }}
|
|
</li>
|
|
<slot name="before-options"></slot>
|
|
<at-option
|
|
v-for="option of options"
|
|
:key="option.id"
|
|
:value="option.id"
|
|
:label="option.name"
|
|
@on-select-close="onClose"
|
|
>
|
|
</at-option>
|
|
</at-select>
|
|
<span v-if="showCount" class="at-select__placeholder">
|
|
{{ placeholderText }}
|
|
</span>
|
|
<i v-if="model.length > 0" class="icon icon-x at-select__clear" @click.stop="clearSelect"></i>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import ResourceService from '../services/resource.service';
|
|
|
|
export default {
|
|
props: {
|
|
service: {
|
|
type: ResourceService,
|
|
},
|
|
selected: {
|
|
type: [String, Number, Array, Object],
|
|
default: Array,
|
|
},
|
|
inputHandler: {
|
|
type: Function,
|
|
},
|
|
prependName: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
showSelectAll: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: 'normal',
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
model: [],
|
|
showCount: true,
|
|
options: [],
|
|
};
|
|
},
|
|
async created() {
|
|
try {
|
|
const all = await this.service.getAll({ headers: { 'X-Paginate': 'false' } });
|
|
this.options.push(...all);
|
|
this.$emit('onOptionsLoad', this.options);
|
|
} catch ({ response }) {
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.warn(response ? response : 'request to projects is canceled');
|
|
}
|
|
}
|
|
|
|
if (Array.isArray(this.selected)) {
|
|
this.model = this.selected;
|
|
}
|
|
|
|
this.$nextTick(() => {
|
|
this.model.forEach(modelValue => {
|
|
if (this.$refs.select && Object.prototype.hasOwnProperty.call(this.$refs.select, '$children')) {
|
|
this.$refs.select.$children.forEach(option => {
|
|
if (option.value === modelValue) {
|
|
option.selected = true;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
this.lastQuery = '';
|
|
this.$watch(
|
|
() => {
|
|
if (this.$refs.select === undefined) {
|
|
return;
|
|
}
|
|
|
|
return {
|
|
query: this.$refs.select.query,
|
|
visible: this.$refs.select.visible,
|
|
};
|
|
},
|
|
({ query, visible }) => {
|
|
if (visible) {
|
|
if (query.length) {
|
|
this.lastQuery = query;
|
|
} else {
|
|
if (
|
|
['input', 'keypress'].includes(window?.event?.type) ||
|
|
window?.event?.key === 'Backspace'
|
|
) {
|
|
// If query changed by user typing, save query
|
|
this.lastQuery = query;
|
|
} else {
|
|
// If query changed by clicking option and so on, restore query
|
|
this.$refs.select.query = this.lastQuery;
|
|
}
|
|
}
|
|
} else {
|
|
this.lastQuery = query;
|
|
}
|
|
},
|
|
);
|
|
},
|
|
watch: {
|
|
model(value) {
|
|
if (this.inputHandler) {
|
|
this.inputHandler(value);
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
selectAll(predicate = () => true) {
|
|
if (this.allOptionsSelected) {
|
|
this.model = [];
|
|
} else {
|
|
// console.log(this.$refs.select);
|
|
const query = this.$refs.select.query.toUpperCase();
|
|
this.model = this.options
|
|
.filter(({ name }) => name.toUpperCase().indexOf(query) !== -1)
|
|
.filter(predicate)
|
|
.map(({ id }) => id);
|
|
}
|
|
},
|
|
clearSelect() {
|
|
this.$emit('input', []);
|
|
this.model = [];
|
|
},
|
|
onClick() {
|
|
if (this.showCount) {
|
|
this.showCount = false;
|
|
} else {
|
|
setTimeout(() => {
|
|
this.showCount = true;
|
|
}, 300);
|
|
}
|
|
},
|
|
onClose() {
|
|
this.$refs.select.query = '';
|
|
|
|
if (!this.showCount) {
|
|
setTimeout(() => {
|
|
this.showCount = true;
|
|
}, 300);
|
|
}
|
|
},
|
|
onChange(val) {
|
|
if (this.inputHandler) {
|
|
this.inputHandler(val);
|
|
}
|
|
},
|
|
},
|
|
computed: {
|
|
selectionAmount() {
|
|
return this.model.length;
|
|
},
|
|
allOptionsSelected() {
|
|
return this.options.length > 0 && this.options.length === this.selectionAmount;
|
|
},
|
|
placeholderText() {
|
|
const i18nKey = this.placeholder + (this.allOptionsSelected ? '_all' : '');
|
|
return this.$tc(i18nKey, this.selectionAmount, {
|
|
count: this.selectionAmount,
|
|
});
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.at-select-wrapper {
|
|
position: relative;
|
|
}
|
|
|
|
.at-select {
|
|
min-width: 240px;
|
|
|
|
&__placeholder {
|
|
left: 0;
|
|
position: absolute;
|
|
z-index: 1;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
&--small ~ &__placeholder {
|
|
font-size: 11px;
|
|
padding: 5px 24px 0 8px;
|
|
}
|
|
|
|
&__clear {
|
|
margin-right: $spacing-05;
|
|
display: block;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
::v-deep {
|
|
.at-select {
|
|
&__placeholder {
|
|
color: #3f536d;
|
|
padding: 10px 12px;
|
|
}
|
|
|
|
&__input {
|
|
height: 100%;
|
|
z-index: 2;
|
|
}
|
|
|
|
&__selection {
|
|
border-radius: 5px;
|
|
color: black;
|
|
}
|
|
|
|
&--visible + .at-select__placeholder {
|
|
display: none;
|
|
}
|
|
|
|
&__clear {
|
|
z-index: 3;
|
|
}
|
|
|
|
&__arrow {
|
|
z-index: 3;
|
|
}
|
|
}
|
|
|
|
.at-tag {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|