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

Validate form input fields in child component from a parent component with 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".

有什么想法吗?谢谢。

我已经找到了这个验证的另一种解决方案,非常简单。父组件中的子组件:

<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())
...

在父组件上提交表单期间尝试验证子组件时遇到类似问题。我的子组件只有一层深,所以如果你有更深的嵌套,这种方式可能不起作用,或者你必须递归检查或其他东西。可能有更好的检查方法,但这对我有用。祝你好运。

// 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
      }
   }

我遇到了同样的问题。这是我为解决它所做的工作。

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

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

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

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

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

  1. 现在要向用户显示正确的错误,我们将 $touch child 表单。为此,我们需要在 above-created 事件池中发出一个事件,我们的 child 将订阅该事件。

parent:

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

child:

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

希望对您有所帮助:)

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

最后,我使用了 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() {
    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 中的错误传达给组件本身,但这种方法让我在发生错误时暂停表单提交。

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

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