vue.jsvuejs3vue-componentvue-props

How to wait for a prop to change as part of a function?


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:

  1. User submits the form which runs sendForm() in Form.vue
  2. sendForm() tells the Parent.vue that it is publishing
  3. Parent.vue does a validation check using validateRecord()
  4. If validateRecord fails validation, then props.PassedParentValidation should be false and throw an error in Form.vue
  5. If 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 error

What 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?


Solution

  • 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>