最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

vue.js - How to wait for a prop to change as part of a function? - Stack Overflow

matteradmin9PV0评论

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?

SomeReallyComplexConditionThatCouldTake10SecondsToComplete is currently just checking if some data exists in the parent e.g. Array.isArray(MyData) && MyData.length but it will grow to accomodate many checks in the parent. I cannot know how complex it will be become.

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?

SomeReallyComplexConditionThatCouldTake10SecondsToComplete is currently just checking if some data exists in the parent e.g. Array.isArray(MyData) && MyData.length but it will grow to accomodate many checks in the parent. I cannot know how complex it will be become.

Share Improve this question edited Nov 17, 2024 at 12:47 volume one asked Nov 16, 2024 at 21:14 volume onevolume one 7,58314 gold badges90 silver badges173 bronze badges 5
  • 1 Please, show what SomeReallyComplexConditionThatCouldTake10SecondsToComplete, etc really are. If they are really async ops then a way to solve this is to use a callback rather than event handler. I.e it would be :onPublishing="validateRecord" and await props.onPublishing(). There aren't many cases when callback props are suitable in vue but this is one of them – Estus Flask Commented Nov 16, 2024 at 22:52
  • @EstusFlask the complex condition will grow over time. at the moment it just checks if some data exists in the parent and then sets PassedValidation.value = true> – volume one Commented Nov 17, 2024 at 11:14
  • If it's synchronous then nextTick will work, but then it's unclear why validateRecord is "async" – Estus Flask Commented Nov 17, 2024 at 11:25
  • 1 I see. await props.onPublishing() instead of context.emit('Publishing'), :onPublishing="validateRecord" instead of @Publishing="validateRecord". This presumes that validateRecord can be asynchronous as its signature suggests, e.g. have server-side validation. Had the same case with forms, a callback instead of an event solved this – Estus Flask Commented Nov 17, 2024 at 12:57
  • @EstusFlask tried to edit my comment but had to delete it. thanks for the extra info. – volume one Commented Nov 17, 2024 at 12:58
Add a comment  | 

1 Answer 1

Reset to default 0

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>
Post a comment

comment list (0)

  1. No comments so far