Search code examples
javascriptvue.jsinfinite-loop

How to prevent the following Vue watch from triggering an infinite loop?


I have an object that looks like this:

visitorInfo: {
  name: {
    name: 'Name',
    value: '',
    isInvalid: false,
    errors: []
  },
  email: {
    name: 'Email address',
    value: '',
    validation: {
      isRequired: true
    },
    errors: []
  },
  phone: {
    name: 'Phone number',
    value: '',
    errors: []
  }
},

I'm using watch to add error messages when the value of the fields changes (e.g. when the user is typing in a form):

fields: {
  handler (fields) {
    Object.entries(fields).forEach(([key, value]) => {
      const field = fields[key]
      const isRequired = field.validation.isRequired && field.value
      if (isRequired) {
        field.errors.push({
          errorType: 'isRequired',
          message: 'This field is required.'
        })
      }
    })
  },
  deep: true
}

But as you can see there's a problem. This bit

field.errors.push({
  errorType: 'isRequired',
  message: 'This field is required.'
})

Will trigger an endless lop since it's modifying fields.

How to solve this issue?


Solution

  • Since vue cannot detect if you directly modify an array element, this might help:

    field.errors[field.errors.length] = {
      errorType: 'isRequired',
      message: 'This field is required.'
    };
    

    Another option would be to simply check if the error has already been reported:

    if (isRequired && !field.errors.length) { ... }
    

    The downside of this is that it will still trigger the watcher an unnecessary 2nd time.

    Let me know how it goes.