I'm trying to write a single computed property that will match 2 reactive variables, by make it dynamic. I'm using Typescript, Vue3-Composition API and PrimeVue.
Using Prime Vue I have 2 similar MultiSelect components with this structure:
<MultiSelect
v-model="selectedClients"
:selected-items-label="itemsSelected"
:options="clientsList"
option-label="firstName"
option-value="id"
/>
<MultiSelect
v-model="selectedCars"
:selected-items-label="itemsSelected"
:options="carsList"
option-label="carType"
option-value="id"
/>
I want to bind selected-items-label to a computed property itemsSelected, something like this:
const itemsSelected = computed((selector: any) => {
return selector.value.length > 1 ? "{0} items selected" : "{0} item selected";
});
I know I can use 2 diferent computed properties just by changing between selectedClients and selectedCars, but this seems to be redundant.
const accountsItemsSelected = computed(() => {
return selectedClients.value.length > 1
? "{0} items selected"
: "{0} item selected";
});
Can I pass a dynamic param to a computed property to achieve this with a single computed prop ?
You could use a higher order function:
const counter = computed(
() =>
({ length }) =>
`${length || 'No'} item${length === 1 ? '' : 's'} selected`
)
Usage:
<MultiSelect
v-model="selectedClients"
:selected-items-label="counter(selectedClients)"
:options="clientsList"
option-label="firstName"
option-value="id"
/>
<MultiSelect
v-model="selectedCars"
:selected-items-label="counter(selectedCars)"
:options="carsList"
option-label="carType"
option-value="id"
/>
Demo.
Note: In the example above, the ref passed has to have a value with .length
(an array or a string) at all times.
If it's ever falsey (false
, null
, undefined
, etc...), it will error.
To allow falsey values, change it to:
const counter = computed(
() => (r) => `${r?.length || 'No'} item${r?.length === 1 ? '' : 's'} selected`
)