0👍
You shouldn’t be meddling with children’s data from the parent. That would be a tight coupling. Try the "dumb component" style, where your input
s are only display components & accept props & emit data to the parent. This way you can validate the data in the parent, in any way you want.
A bit more complex solution would be to create the error-handlers inside your "dumb components", and only emit back "error" if they detect errors in themselves. Another style could be to create the validation functions in your fields
dataset & just pass down the functions themselves (more of a React than a Vue approach – totally working & valid JS, just not really Vue-style).
In the snippet below I just added value
& error
to the field items, so they are fully present in the parent component.
Vue.component("InputPassword", {
props: ['field'],
computed: {
value: {
get() {
return this.field.value
},
set(value) {
this.$emit("update:value", {
value
})
}
},
},
template: `
<div>
<label>{{ field.name }}: <input type="password" v-model="value" /></label>
<span
v-if="field.error"
>
THIS FIELD HAS ERRORS
</span>
</div>
`
})
Vue.component("InputText", {
props: ['field'],
computed: {
value: {
get() {
return this.field.value
},
set(value) {
this.$emit("update:value", {
value
})
}
},
},
template: `
<div>
<label>{{ field.name }}: <input type="text" v-model="value" /></label>
<span
v-if="field.error"
>
THIS FIELD HAS ERRORS
</span>
</div>
`
})
new Vue({
el: "#app",
data() {
return {
fields: [{
"name": "nombreDeUsuario",
"label": "Nombre de Usuario",
"type": "text",
"placeholder": "Ingresa Usuario",
"value": null,
"error": null,
},
{
"name": "passwordUsuario",
"label": "Password",
"type": "password",
"placeholder": "Contraseña",
"value": null,
"error": null,
},
]
}
},
computed: {
isFormValid() {
return this.fields.every(({
error
}) => error == false) ? "YES" : "NO"
}
},
methods: {
handleValidateForm() {
this.fields = this.fields.map(field => {
return {
...field,
error: !(!!field.value) // valid if not empty
}
})
},
},
template: `
<div>
<form>
<component
v-for="field in fields"
v-bind:is="'input-' + field.type"
v-bind="{
field
}"
v-on="{
'update:value': ({ value }) => {
field.value = value
},
}"
></component>
</form>
<div
v-for="(field, i) in fields"
:key="'display-field-' + i"
>
field name: {{ field.name }}<br />
field value: {{ field.value }}
</div>
<hr />
<button
@click="handleValidateForm"
>
VALIDATE
</button>
IS FORM VALID? {{ isFormValid }}
</div>
`
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<div id="app"></div>
- [Vuejs]-Control Vue component from nested layout using Inertia JS
- [Vuejs]-VueJS child component button changes class of parent