I'm in the process of converting my app from Vue2 to Vue3, but have gotten stalled out on one aspect of my forms.
I'm using SFCs for form element components (FormInput, FormTextArea, FormCheckbox, etc.), and passing them into form container components (FormGroup, FormTab, etc) using slots, like so:
<ssi-form>
<ssi-form-tabs>
<ssi-form-tab title="tab1">
<ssi-form-input title="name" ... />
<ssi-form-checkbox title="active" ... />
</ssi-form-tab>
</ssi-form-tabs>
</ssi-form>
Those parent containers need to view some computed properties of the child form elements to pull error messages to the top.
In Vue2, I used the mounted lifecycle hook (with the options API) to read the slots and access the computed properties, like this:
mounted: function() {
const vm = this;
this.$slots.default.forEach((vNode) => {
const vueComponent = vNode.componentInstance;
vueComponent.$on("invalid", vm.onInvalid);
if (vueComponent.errorCount === undefined) return;
this.childFormElements.push(vueComponent);
});
},
Using this setup, I could grab the errorCount
computed property from each child in the slot, so I could aggregate errors going up to the top level of the form.
Now that I'm switching to Vue3, it seems like componentInstance
doesn't exist. I tried setting up similar logic using the onMounted
directive, but when I access the slot elements, I can't find any way to see their errorCount
computed property:
onMounted(() => {
slots.default().forEach((vNode) => {
console.log(vNode);
});
});
The logged object does not contain the computed property. I thought I found something useful when I read about defineExpose
, but even after exposing the errorCount
property, nothing comes up.
Here is the <script setup>
from the SFC for the text input that I'm trying to work with:
<script setup lang="ts">
import { ref, defineProps, defineEmits, computed } from "vue";
let props = defineProps<{
label: string,
id: string,
modelValue: string|number,
type?: string,
description?: string,
min?: string|number,
max?: string|number,
pattern?: string,
message?: string
}>();
let emit = defineEmits(["input", "update:modelValue", "invalid"]);
let state = ref(null);
let error = ref("");
const input = ref(null);
function onInput(event: Event) {
validate();
emit('update:modelValue', event.target.value)
}
// methods
function validate() {
let inputText = input.value;
if (inputText === null) return;
inputText.checkValidity();
state.value = inputText.validity.valid;
error.value = inputText.validationMessage;
}
const errorCount = computed(() => {
return state.value === false ? 1 : 0;
});
defineExpose({errorCount})
</script>
So the question is - how can a parent component read the errorCount
property from a component placed into a slot?
from Vue3 equivalent of vNode.computedInstance
No comments:
Post a Comment