I'm using Pinia as Store for my Vue 3 application. The problem is that the store reacts on some changes, but ignores others.
The store looks like that:
state: () => {
return {
roles: [],
currentRole: 'Administrator',
elements: []
}
},
getters: {
getElementsForCurrentRole: (state) => {
let role = state.roles.find((role) => role.label == state.currentRole);
if (role) {
return role.permissions.elements;
}
}
},
In the template file, I communicate with the store like this:
<template>
<div>
<draggable
v-model="getElementsForCurrentRole"
group="elements"
@end="onDragEnd"
item-key="name">
<template #item="{element}">
<n-card :title="formatElementName(element.name)" size="small" header-style="{titleFontSizeSmall: 8px}" hoverable>
<n-switch v-model:value="element.active" size="small" />
</n-card>
</template>
</draggable>
</div>
</template>
<script setup>
import { NCard, NSwitch } from 'naive-ui';
import draggable from 'vuedraggable'
import { usePermissionsStore } from '@/stores/permissions';
import { storeToRefs } from 'pinia';
const props = defineProps({
selectedRole: {
type: String
}
})
const permissionsStore = usePermissionsStore();
const { getElementsForCurrentRole, roles } = storeToRefs(permissionsStore);
const onDragEnd = () => {
permissionsStore.save();
}
const formatElementName = (element) => {
let title = element.charAt(0).toUpperCase() + element.slice(1);
title = title.replace('-', ' ');
title = title.split(' ');
if (title[1]) {
title = title[0] + ' ' + title[1].charAt(0).toUpperCase() + title[1].slice(1);
}
if (typeof title == 'object') {
return title[0];
}
return title;
}
</script>
My problem is the v-model="getElementsForCurrentRole". When making changes, for example changing the value for the switch, the store is reactive and the changes are made successfully. But: If I try to change the Array order by dragging, the store does not update the order. I'm confused, because the store reacts on other value changes, but not on the order change.
What can be the issue here? Do I something wrong?
-Edit- I see the following warning on drag: Write operation failed: computed value is readonly
Workaround
As workaround I work with the drag event and write the new index directly to the store variable. But...its just a workaround. I would really appreciate a cleaner solution.
Here is the workaround code:
onDrag = (event) => {
if (event && event.type == 'end') {
// Is Drag Event. Save the new order manually directly in the store
let current = permissionsStore.roles.find((role) => role.value == permissionsStore.currentRole);
var element = current.permissions.elements[event.oldIndex];
current.permissions.elements.splice(event.oldIndex, 1);
current.permissions.elements.splice(event.newIndex, 0, element);
}
}