In our project we have a list components, which renders a list of a group of items, one of which can be edited at a time. It uses slots to get what to render for each item. Simplified, it looks a little like this:
<template>
<div>
<div v-for="item in items">
<slot name="display" :item="item" v-if="!editing(item)"></slot>
<slot name="edit" :item="item" v-else></slot>
</div>
<button @click="clickDone">Done</button>
</div>
<template>
<script>
export default {
props: ["items"],
methods: {
clickDone() {
...
}
}
}
This is used in another component that needs to display an editable list of complex of objects. It looks a little like this:
<EditableList :items="listOfComplexObjects">
<template #edit="item">
<component :is="item.componentType" v-model="item" />
</template>
</EditableList>
There is then a number of different components that could be rendered for each item in the list, depending on what type it is.
In the first code snippet you can see the 'Done' button. This button is what the list uses to turn an 'editable' item into a 'display' item. The problem we've run into is we'd like to invoke validation on the click of this button. However the validation is going to be different for each item type component. Also the validation needs to mark certain fields in the item type component as invalid and show error messages on them. So this validation makes most sense to live within the item type components. So we are trying to consider how to the 'Done' button to call a validation method on a component within the slot.
What we've considered:
by using a ref on the 'component' we can use something like
this.$parent.refs.refName.validateto invoke the validator from within the editable list. The problem with this is it breaks encapsulation between the editable list, the parent component and the list item components.moving the 'done' button into the list item components. Clicking the done button will invoke local validation and then emit an event which the parent component will pass on to the editable list to manipulate it's internal state. This solution is our current best but it feels like it adds unnecessary boiler plate code to the non-editable list components.
What we wish we could do:
- have each list item component implement a validate method that the parent component passes into the editable list as a kind of 'slot' or prop specific to each item. Then the editable list can invoke that validation method on the click of done and the list item component can update its state with error messages.
How can the above most easily and correctly be achieved in Vue.js?