使用Vuelidate从父组件验证子组件中的表单输入字段

时间:2018-12-05 08:55:33

标签: vue.js vuejs2 vue-component vuelidate

我是Vue Js和Vuelidate的新手。刚刚尝试验证来自父组件的表单输入字段,例如:https://github.com/monterail/vuelidate/issues/333

父级中的子级组件

<contact-list ref="contactList" :contacts="contacts" @primaryChanged="setPrimary" @remove="removeContact" @ready="isReady => readyToSubmit = isReady"/>

子级中的方法:

computed: {
    ready() {
        return !this.$v.email.$invalid;
    }
},
watch: {
    ready(val) {
        this.$emit('ready', val);
    }
},

methods: {
    touch() {
        this.$v.email.$touch();
    }
}

我像这样从父级调用touch()方法:

submit() {
            this.$refs.contactList.touch();
        },

但我收到此错误:

Error in event handler for "click": "TypeError: this.$refs.contactList.touch is not a function".

有什么想法吗?谢谢。

4 个答案:

答案 0 :(得分:1)

我面临着同样的问题。这是我为解决该问题所做的事情。

  1. 创建了一个全局事件池。我可以使用$emit发出事件,而我的孩子可以使用$on$once进行订阅,并使用$off取消订阅。在您的app.js内粘贴以下代码。下面是事件池操作的列表。

    • 发射:this。$ eventPool。$ emit()
    • 打开:this。$ eventPool。$ on()
    • 关闭:this。$ eventPool。$ off()
    • 一次:this。$ eventPool。$ once()

Vue.prototype.$eventPool = new Vue();

  1. 在子组件内部,我在watch上创建了$v,如下所示。它将表单的状态发送给父组件。
watch: {
    "$v.$invalid": function() {
      this.$emit("returnStatusToParent", this.$v.$invalid);
    }
  }
  1. 现在父组件内部将处理以下状态。

<ChildComponent @returnStatusToParent="formStatus =>isChildReady=formStatus"></ChildComponent>

  1. 现在要向用户显示正确的错误,我们将$touch子窗体。为此,我们需要在上面创建的事件池中发出一个事件,我们的孩子将订阅该事件。

父母:

this.$eventPool.$emit("touchChildForm");

孩子:

 mounted() {
    this.$eventPool.$on("touchChildForm", () => {
      this.$v.$touch();
      this.$emit("returnStatusToParent", this.$v.$invalid);
    });
  },
  destroyed() {
    this.$eventPool.$off("touchChildForm", () => `{});`
  }

希望它会有所帮助:)

答案 1 :(得分:0)

我已经找到了另一种验证方法,这很简单。父项中的子项:

<contact-list ref="customerContacts" :contacts="customer.contacts" />

子组件中的验证

:validator="$v.model.$each[index].name
...
validations: {
    model: {
        required,
        $each: {
            name: {
                required
            },
            email: {
                required,
                email
            },
            phone: {
                required
            }
        }

    }

}

在父级提交时

async onSubmit() {
            if(this.$refs.customerContacts.valid())
...

答案 2 :(得分:0)

在提交有关父组件的表单期间尝试验证子组件时遇到类似的问题。我的子组件只有一层,因此,如果您有更深的嵌套,则这种方式可能无法正常工作,或者您必须进行递归检查。可能有更好的检查方法,但这对我有用。祝你好运。

// parent component
  methods: {
    onSave() {
      let formIsInvalid = this.$children.some(comp => {
        if (comp.$v) { // make sure the child has a validations prop
          return comp.$v.$invalid
        }
      })

      if (!formIsInvalid) {          
        // submit data
      }          
      else {
        // handle invalid form
      }
   }

答案 3 :(得分:0)

在这个问题已经有一个公认的解决方案之后,我正在添加我的答案,但仍然希望它可以帮助其他人。我整个星期都在做这件事。上述解决方案都不适用于我的场景,因为有嵌套 2 层深的子组件,因此当我需要最大的父组件来触发所有验证并能够知道表单是否有效时,“ref”方法将不起作用。

最后,我使用了带有相当简单的消息模块的 vuex。这是那个模块:

const state = {
  displayMessages: [],
  validators: []
};

const getters = {
  getDisplayMessages: state => state.displayMessages,
  getValidators: state => state.validators
};

const actions = {};

const mutations = {
  addDisplayMessage: (state, message) => state.displayMessages.push(message),
  addValidator: (state, validator) => {
    var index = 0;
    while (index !== -1) {
      index = _.findIndex(state.validators, searchValidator => {
        return (
          searchValidator.name == validator.name &&
          searchValidator.id == validator.id
        );
      });
      if (index !== -1) {
        console.log(state.validators[index]);
        state.validators.splice(index, 1);
      }
    }

    state.validators.push(validator);
  }
};

export default {
  state,
  getters,
  actions,
  mutations
};

然后每个组件在它的mounted事件中都有这个:

  mounted() {
    this.addValidator( {name: "<name>", id: 'Home', validator: this.$v}) ;
  }

现在当用户点击主页上的“提交”按钮时,我可以像这样触发所有验证:

  this.getValidators.forEach( (v) => {
    console.log(v);
    v.validator.$touch();
  });

我可以很容易地检查 vuelidate 对象的 $error、$invalid 属性。根据我的测试,vuelidate 反应性保持不变,因此即使将对象保存到 vuex,组件字段上的任何更改也会按预期反映。

我打算留下消息和样式来将 gui 中的错误传达给组件本身,但是这种方法让我可以在发生错误时暂停表单提交。

这是一件好事吗?老实说,我不知道。如果在添加验证器之前必须删除验证器,这是唯一的错误。我认为这更多是我的组件逻辑问题,而不是作为验证解决方案的问题。

考虑到这花了我整整一周的时间,我对解决方案非常满意,但欢迎任何反馈。