koumoul-dev / vuetify-jsonschema-form

Create beautiful and low-effort forms that output valid data. Published on npm as @koumoul/vjsf.
https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/
MIT License
538 stars 154 forks source link

Custom Component Not Validating #263

Closed stefanadelbert closed 3 years ago

stefanadelbert commented 3 years ago

I'm struggling to get intial validation working on a custom component. I am setting initialValidation='all' in options, but the custom component does not validate when the form is first mounted.

The custom component does validate when I explicitly validate the form, i.e. this.$refs.form.validate.

Below is a very basic custom component which doesn't validate.

<template>
    <v-input
        :name="fullKey"
        :label="label"
        :disabled="disabled"
        :rules="rules"
        :required="required"
    >
        <v-text-field type="number" @input="onInput"></v-text-field>
    </v-input>
</template>

<script>
export default {
    props: {
        value: { type: Number },
        options: { type: Object, required: true },
        schema: { type: Object, required: true },
        fullSchema: { type: Object, required: true },
        fullKey: { type: String, required: true },
        label: { type: String, default: '' },
        htmlDescription: { type: String, default: '' },
        disabled: { type: Boolean, default: false },
        required: { type: Boolean, default: false },
        rules: { type: Array, required: true },
        on: { type: Object, required: true },
    },
    methods: {
        onInput(value) {
            this.on.input(value)
        },
    },
}
</script>
<style scoped></style>

I have spent a lot of time looking into Vuetify VForm validation and also at the source code for VJSF validation. I'm struggling to understand how the two validation mechanisms work together. Please help me to get the initial validation working for a custom component like the one above.

albanm commented 3 years ago

Validation is tricky. I will try to investigate your problem soon, but just a few things on the top of my head about the way it works:

It looks like the input in your custom component doesn't register into its parent vjsf instance, but instead directly to the root form. Either that or something goes wrong in the initValidation+register+validate sequence. The way I would try to solve this is by running the dev server, creating a new example matching the scenario with as little properties and options as possible, and debugging. This example could then stay either as part of the doc if it is informative for users, or hidden just for regression testing.

albanm commented 3 years ago

I just checked, it looks like everything works fine on my side.

I think what you are missing is :value="value" on the v-input, this is necessary for the rules to be evaluated correctly.

stefanadelbert commented 3 years ago

Thank you very much for your feedback and suggestions. I hope that including ':value="value"' works in my case. If not I will get the dev server running and attempt to replicate any issues I see (good suggestion!).

It's really useful to have some insight into the mechanics, so thank you for that. I did notice the tree of 'inputs' being built recursively, but I now have a better idea of how it all hangs together which helps.

On Wed, 23 Jun. 2021, 1:23 am Alban Mouton, @.***> wrote:

I just checked, it looks like everything works fine on my side.

I think what you are missing is :value="value" on the v-input, this is necessary for the rules to be evaluated correctly.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/koumoul-dev/vuetify-jsonschema-form/issues/263#issuecomment-866080742, or unsubscribe https://github.com/notifications/unsubscribe-auth/AATMRTK3U3S2OJB6D4AVUCDTUCTGTANCNFSM47DBHRBQ .

stefanadelbert commented 3 years ago

I realised that I was still on ^1.25.0, so I upgraded to ^2.0.0 (actually 2.0.3) and now the validation is working as expected.

This is a simplified version of the custom component (notice that I'm extending VInput) and it's working as expected.

<template>
    <div>
        <v-rating
            :value="value"
            v-on="{ ...on, input }"
            class="px-4"
            color="primary"
            :background-color="isValidationError ? 'error' : 'primary'"
            x-large
        />
        <v-messages
            v-if="hasMessages"
            color="error"
            :value="messagesToDisplay"
        />
    </div>
</template>

<script>
import VInput from 'vuetify/es5/components/VInput'
export default {
    extends: VInput,
    name: 'RatingScale',
    props: {
        value: { type: Number },
        options: { type: Object, required: true },
        schema: { type: Object, required: true },
        fullSchema: { type: Object, required: true },
        fullKey: { type: String, required: true },
        label: { type: String, default: '' },
        htmlDescription: { type: String, default: '' },
        disabled: { type: Boolean, default: false },
        required: { type: Boolean, default: false },
        rules: { type: Array, required: true },
        on: { type: Object, required: true },
    },
    methods: {
        input(value) {
            this.on.input(value)
        },
    },
    computed: {
        isValidationError() {
            return this.validationState === 'error'
        },
    },
}
</script>

<style scoped></style>

Note I'm using validationState and hasMessages to determine whether to render the component in the error state. Is there a better or "more correct" way to do that?

Note I had mentioned in a previous edit of this message that I was having problems getting doc-dev running, but I realised that I had removed package-lock.json. I restored package-lock.json and ran npm install && npm run doc-dev without problems.

albanm commented 3 years ago

Nice example of a custom component ! Extending v-input and using its validation state seems like a good idea to me.