fix(controls): link and multiselect filter handling

This commit is contained in:
raizasafeel
2026-03-17 00:16:13 +05:30
parent e2550cca31
commit 5d8090c0a0
2 changed files with 36 additions and 31 deletions
+2 -2
View File
@@ -140,7 +140,7 @@ const options = createResource({
params: {
txt: text.value,
doctype: props.doctype,
filters: props.filters,
filters: JSON.stringify(props.filters),
},
transform: (data) => {
return data.map((option) => {
@@ -158,7 +158,7 @@ const reload = (val) => {
params: {
txt: val,
doctype: props.doctype,
filters: props.filters,
filters: JSON.stringify(props.filters),
},
})
options.reload()
@@ -10,6 +10,7 @@
ref="search"
class="form-input w-full focus-visible:!ring-0"
type="text"
:displayValue="() => query"
@change="
(e) => {
query = e.target.value
@@ -106,7 +107,7 @@ import {
ComboboxOptions,
ComboboxOption,
} from '@headlessui/vue'
import { createResource, Button } from 'frappe-ui'
import { createResource, Button, toast } from 'frappe-ui'
import { ref, computed, useAttrs, watch } from 'vue'
import { watchDebounced } from '@vueuse/core'
import { X, Plus } from 'lucide-vue-next'
@@ -115,7 +116,9 @@ const props = defineProps({
label: String,
size: { type: String, default: 'sm' },
doctype: { type: String, required: true },
filters: { type: Object, default: () => ({}) },
filters: { type: [Object, Array], default: () => ({}) },
url: { type: String, default: 'frappe.desk.search.search_link' },
searchParams: { type: Object, default: () => ({}) },
validate: Function,
errorMessage: {
type: Function,
@@ -124,22 +127,18 @@ const props = defineProps({
required: Boolean,
})
const values = defineModel()
const values = defineModel({ default: () => [] })
const attrs = useAttrs()
const trigger = ref(null)
const query = ref('')
const text = ref('')
const selectedValue = ref(null)
const error = ref(null)
const emit = defineEmits(['update:modelValue'])
watch(selectedValue, (val) => {
if (!val?.value) return
query.value = ''
addValue(val.value)
selectedValue.value = null
emit('update:modelValue', values.value)
})
watchDebounced(
@@ -153,14 +152,27 @@ watchDebounced(
{ debounce: 300, immediate: true }
)
const filterOptions = createResource({
url: 'frappe.desk.search.search_link',
method: 'POST',
auto: true,
params: {
txt: text.value,
doctype: props.doctype,
// Refetch when filters or searchParams change
watch(
() => [props.filters, props.searchParams],
() => {
reload(text.value)
},
{ deep: true }
)
function getParams(txt) {
return {
txt,
doctype: props.doctype,
filters: JSON.stringify(props.filters),
...props.searchParams,
}
}
const filterOptions = createResource({
url: props.url,
method: 'POST',
})
const options = computed(() => {
@@ -170,10 +182,7 @@ const options = computed(() => {
function reload(val) {
filterOptions.update({
params: {
txt: val,
doctype: props.doctype,
},
params: getParams(val),
})
filterOptions.reload()
}
@@ -186,34 +195,30 @@ function onFocus() {
}
function addValue(value) {
error.value = null
if (!value) return
const splitValues = value.split(',')
let newValues = [...(values.value || [])]
splitValues.forEach((val) => {
val = val.trim()
if (!val) return
if (values.value?.includes(val)) return
if (newValues.includes(val)) return
if (props.validate && !props.validate(val)) {
error.value = props.errorMessage(val)
toast.error(props.errorMessage(val))
return
}
if (!values.value) values.value = [val]
else values.value.push(val)
newValues.push(val)
})
values.value = newValues
}
function removeValue(value) {
let indexToRemove = values.value.indexOf(value)
if (indexToRemove > -1) {
values.value.splice(indexToRemove, 1)
}
emit('update:modelValue', values.value)
values.value = values.value.filter((v) => v !== value)
}
const labelClasses = computed(() => [