mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-02 04:39:54 -05:00
212 lines
7.3 KiB
Vue
212 lines
7.3 KiB
Vue
<template>
|
|
<multiselect
|
|
:id="id"
|
|
v-model="selected_objects"
|
|
:options="objects"
|
|
:close-on-select="true"
|
|
:clear-on-select="multiple"
|
|
:hide-selected="multiple"
|
|
:preserve-search="true"
|
|
:internal-search="false"
|
|
:limit="limit"
|
|
:placeholder="lookupPlaceholder"
|
|
:label="label"
|
|
track-by="id"
|
|
:multiple="multiple"
|
|
:taggable="allow_create"
|
|
:tag-placeholder="create_placeholder"
|
|
:loading="loading"
|
|
@search-change="search"
|
|
@input="selectionChanged"
|
|
@tag="addNew"
|
|
@open="selectOpened()"
|
|
>
|
|
</multiselect>
|
|
</template>
|
|
|
|
<script>
|
|
import Vue from "vue"
|
|
import Multiselect from "vue-multiselect"
|
|
import {ApiMixin, StandardToasts} from "@/utils/utils"
|
|
|
|
export default {
|
|
name: "GenericMultiselect",
|
|
components: {Multiselect},
|
|
mixins: [ApiMixin],
|
|
data() {
|
|
return {
|
|
// this.Models and this.Actions inherited from ApiMixin
|
|
id: undefined,
|
|
loading: false,
|
|
objects: [],
|
|
selected_objects: undefined,
|
|
}
|
|
},
|
|
props: {
|
|
placeholder: {type: String, default: undefined},
|
|
model: {
|
|
type: Object,
|
|
default() {
|
|
return {}
|
|
},
|
|
},
|
|
label: {type: String, default: "name"},
|
|
parent_variable: {type: String, default: undefined},
|
|
limit: {type: Number, default: 25},
|
|
sticky_options: {
|
|
type: Array,
|
|
default() {
|
|
return []
|
|
},
|
|
},
|
|
initial_selection: {
|
|
type: Array,
|
|
default() {
|
|
return []
|
|
},
|
|
},
|
|
initial_single_selection: {
|
|
type: Object,
|
|
default: undefined,
|
|
},
|
|
search_on_load: {type: Boolean, default: true},
|
|
multiple: {type: Boolean, default: true},
|
|
allow_create: {type: Boolean, default: false},
|
|
create_placeholder: {type: String, default: "You Forgot to Add a Tag Placeholder"},
|
|
clear: {type: Number},
|
|
},
|
|
watch: {
|
|
initial_selection: function (newVal, oldVal) {
|
|
// watch it
|
|
this.selected_objects = newVal
|
|
let get_details = []
|
|
let empty = {}
|
|
empty[this.label] = `..${this.$t("loading")}..`
|
|
this.selected_objects.forEach((x) => {
|
|
if (typeof x !== "object") {
|
|
this.selected_objects[this.selected_objects.indexOf(x)] = {...empty, id: x}
|
|
get_details.push(x)
|
|
}
|
|
})
|
|
get_details.forEach((x) => {
|
|
this.genericAPI(this.model, this.Actions.FETCH, {id: x})
|
|
.then((result) => {
|
|
// this.selected_objects[this.selected_objects.map((y) => y.id).indexOf(x)] = result.data
|
|
Vue.set(this.selected_objects, this.selected_objects.map((y) => y.id).indexOf(x), result.data)
|
|
})
|
|
.catch((err) => {
|
|
this.selected_objects = this.selected_objects.filter((y) => y.id !== x)
|
|
})
|
|
})
|
|
},
|
|
initial_single_selection: function (newVal, oldVal) {
|
|
// watch it
|
|
this.selected_objects = newVal
|
|
if (typeof this.selected_objects !== "object") {
|
|
let empty = {}
|
|
empty[this.label] = `..${this.$t("loading")}..`
|
|
this.selected_objects = {...empty, id: this.selected_objects}
|
|
this.genericAPI(this.model, this.Actions.FETCH, {id: this.selected_objects})
|
|
.then((result) => {
|
|
this.selected_objects = result.data
|
|
})
|
|
.catch((err) => {
|
|
this.selected_objects = undefined
|
|
})
|
|
}
|
|
},
|
|
clear: function (newVal, oldVal) {
|
|
if (this.multiple || !this.initial_single_selection) {
|
|
this.selected_objects = []
|
|
} else {
|
|
this.selected_objects = undefined
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
this.id = Math.random()
|
|
if (this.search_on_load) {
|
|
this.search("")
|
|
}
|
|
if (this.multiple || !this.initial_single_selection) {
|
|
this.selected_objects = this.initial_selection
|
|
} else {
|
|
this.selected_objects = this.initial_single_selection
|
|
}
|
|
},
|
|
computed: {
|
|
lookupPlaceholder() {
|
|
return this.placeholder || this.model.name || this.$t("Search")
|
|
},
|
|
nothingSelected() {
|
|
if (this.multiple || !this.initial_single_selection) {
|
|
return this.selected_objects?.length === 0 && this.initial_selection?.length === 0
|
|
} else {
|
|
return !this.selected_objects && !this.initial_single_selection
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
// this.genericAPI inherited from ApiMixin
|
|
search: function (query) {
|
|
|
|
let options = {
|
|
page: 1,
|
|
pageSize: this.limit,
|
|
query: query,
|
|
limit: this.limit,
|
|
options: {query: {simple: 1}}, // for API endpoints that support a simple view
|
|
}
|
|
|
|
this.genericAPI(this.model, this.Actions.LIST, options).then((result) => {
|
|
this.objects = this.sticky_options.concat(result.data?.results ?? result.data)
|
|
if (this.nothingSelected && this.objects.length > 0) {
|
|
this.objects.forEach((item) => {
|
|
// select default items when present in object
|
|
if ("default" in item) {
|
|
if (item.default) {
|
|
if (this.multiple) {
|
|
this.selected_objects = [item]
|
|
} else {
|
|
this.selected_objects = item
|
|
}
|
|
this.selectionChanged()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
},
|
|
selectOpened: function () {
|
|
if (this.objects.length < 1) {
|
|
this.search("")
|
|
}
|
|
},
|
|
selectionChanged: function () {
|
|
this.$emit("change", {var: this.parent_variable, val: this.selected_objects})
|
|
},
|
|
addNew(e) {
|
|
//TODO add ability to choose field name other than "name"
|
|
console.log('CREATEING NEW with -> ', e)
|
|
this.genericAPI(this.model, this.Actions.CREATE, {name: e}).then(result => {
|
|
let createdObj = result.data?.results ?? result.data
|
|
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
|
|
if (this.multiple) {
|
|
this.selected_objects.push(createdObj)
|
|
} else {
|
|
this.selected_objects = createdObj
|
|
}
|
|
this.objects.push(createdObj)
|
|
this.selectionChanged()
|
|
}).catch((r, err) => {
|
|
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
|
|
})
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|
|
|
|
<style scoped></style>
|