vue.jsvuejs2vue-component

Access props value in another props' validator


I want to access a props value in another props' validator:

props: {
  type: {
    type: String,
    default: "standard"
  },
  size: {
    type: String,
    default: "normal",
    validator(value) {
      // below I want to access the props `type` from above.
      return (this.type !== "caution" || this.type !== "primary") && value !== "mega"
    }
  }
}

But I'm getting TypeError: Cannot read property 'type' of undefined. Any idea?


Solution

  • The this variable in a prop's validator does not reference the Vue instance. And, unfortunately, there's no real way to reference another prop's value in a prop's validator function.


    One thing you could do would be to set a watcher on the Vue instance's $props object, setting the immediate option to true so that the watcher fires when the component is created. That watcher could trigger the validation logic where this is a reference to the Vue instance.

    Here's a simple example:

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    
    Vue.component('child', {
      template: '<div></div>',
      props: {
        type: {
          type: String,
          default: "standard"
        },
        size: {
          type: String,
          default: "normal"
        }
      },
      methods: {
        validateProps() {
          if ((this.type === "caution" || this.type === "primary") && this.size === "mega") {
            console.error('Invalid props');
          }
        }
      },
      watch: {
        $props: {
          immediate: true,
          handler() {
            this.validateProps();
          }
        }
      }
    });
    
    new Vue({
      el: '#app'
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <child type="caution" size="mega"></child>
    </div>


    Another option would be to pass an object with a type and size property as a single prop. That way the validator of that prop would have a reference to both values.

    Vue.config.productionTip = false;
    Vue.config.devtools = false;
    
    Vue.component('child', {
      template: '<div></div>',
      props: {
        config: {
          type: Object,
          default: () => ({ type: "standard", size: "normal" }),
          validator({ type, size }) {
            return !((type === "caution" || type === "primary") && size === "mega");
          }
        }
      }
    });
    
    new Vue({
      el: '#app'
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <child :config="{ type: 'caution', size: 'mega'}"></child>
    </div>


    (And just a note: your validation logic is probably incorrect. As it's written, the statement in parenthesis will always evaluate to true. I updated that logic in my examples to be what I think you meant.)