I have a Form.vue
component that is used in other parent components to submit data from the user to the server.
The Form.vue
has a prop to indicate whether its parent component has passed its own validation checks (the parent could be anything from a HR record to a video upload). This is how it goes:
Form.vue
export default {
name: "ComponentForm",
props: {
PassedParentValidation: {
type: Boolean,
default: true
}
},
emits: ['Publishing'],
setup(props, context) {
...
async function sendForm() {
context.emit('Publishing') // Triggers parent to perform its own validation
// not waiting for props to update here
if(!props.PassedParentValidation){
const Err = new Error()
Err.message = 'Failed parent validation'
Err.code = 400;
throw Err;
}
else {
//Send the form
}
}
}
A parent component will use the Form.vue
child component a bit like this:
Parent.vue
<template>
<h1>Your HR record</h1>
<Component-Form :PassedParentValidation="PassedValidation" @Publishing="validateRecord" />
</template>
<script>
import ComponentForm from "../components/Form.vue";
export default {
name: 'ViewParent',
"Component-Form": ComponentForm,
setup() {
const PassedValidation = ref(null);
async function validateRecord(){
if (SomeReallyComplexConditionThatCouldTake10SecondsToComplete) {
PassedValidation.value = true;
} else if (!SomeReallyComplexConditionThatCouldTake10SecondsToComplete) {
PassedValidation.value = false;
}
return {
validateRecord,
PassedValidation
}
}
</script>
Here are the steps that I expect to happen:
sendForm()
in Form.vue
sendForm()
tells the Parent.vue
that it is publishingParent.vue
does a validation check using validateRecord()
validateRecord
fails validation, then props.PassedParentValidation
should be false and throw an error in Form.vue
validateRecord
passes validation, then it sets PassedValidation
to true which should update the prop
in Form.vue
as true
i.e. props.PassedParentValidation === true
and not throw an errorWhat is happening is that Form.vue
is not 'awaiting' the prop.PassedParentValidation
to update before running the rest of the sendForm()
code.
So if props.PassedParentValidation === false
, it throws an error. But if the user submits the form again and PassedValidation === true
in Parent.vue
, then that is not being passed to Form.vue
in time.
That is, Form.vue
is not waiting for the prop to change value and so even if the parent's PassedValidation === true
it still remains false in Form.vue
and throws an error.
How can I overcome this?
You can use a watch to monitor changes to the PassedParentValidation prop and update the internal state accordingly.
<template>
<div>
<!-- Your form here -->
<button @click="sendForm">Submit</button>
</div>
</template>
<script>
export default {
name: "ComponentForm",
props: {
PassedParentValidation: {
type: Boolean,
default: true
}
},
emits: ['Publishing'],
setup(props, { emit }) {
const isParentValid = ref(props.PassedParentValidation); // Internal state to react to prop changes
watch(
() => props.PassedParentValidation,
(newVal) => {
isParentValid.value = newVal; // Update internal state when prop changes
}
);
async function sendForm() {
emit('Publishing'); // Notify parent to perform validation
// Wait for the parent's validation process to complete
await nextTick();
// Check the updated state after validation
if (!isParentValid.value) {
const Err = new Error();
Err.message = 'Failed parent validation';
Err.code = 400;
throw Err;
} else {
// Send the form if validation passes
console.log("Form submitted successfully!");
}
}
return {
sendForm,
isParentValid
};
}
};
</script>