Home > database >  VuetifyJS: Access v-form disabled state in child components
VuetifyJS: Access v-form disabled state in child components

Time:01-21

The Vuetify component v-form knows a disabled property, which is published down to child vuetify components like v-text-field, v-input etc. When the disabled property of the v-form is set to true, all child input fields are also (automatically) disabled.

But this only works for Vuetify v-input-like fields, but it seems that this does not work for own components. I want to be able to "inherit" the disabled prop in a child component (to do my own disabled UI).

I don't want to pass the reactive data prop (formDisabled in my example), as this is too tedious: There would be a large nested bunch of components that all explicitely would need the reactive data prop, which I don't want to implement: Obviously it IS working with Vuetify's own components, but how can I achieve the same by myself?

An example:

<template>
    <v-form :disabled="formDisabled">
        <!-- 
            works, even WITHOUT explicitely binding formDisabled: 
            textfield gets en-/disabled according to the form state: 
        -->
        <v-text-field />

        <!-- does NOT work: Withoud bind the formDisabled prop, 
             I cannot get the form's disabled state in my own component: -->
        <MyOwnComponent />
    </v-form>
    <v-btn @click="formDisabled = !formDisabled">Toggle</v-btn>
</template>

<script>
export default {
    data() {
        return {
            formDisabled: true
        };
    },
};
</script>

So how can I find out the form's disabled state, WITHOUT binding the formDisabled data prop explicitely to every own form child component?

CodePudding user response:

Have a look at v-input, it is the base for Vuetify inputs, you can use it to build Vuetify-like inputs which resolve disabled state (and all other validation) same as other Vuetify components.

If this does not work for you, you can manually resolve the disabled state similar to what Vuetify/v-input does, where the disabled state is propagated from form to inputs through injection.

In Vuetify 3, I can inject the form like this (using composition API):

const form = inject(Symbol.for("vuetify:form"))

or like this:

import {useForm} from 'vuetify/lib/composables/form'
const form = useForm()

which gives me an object of this interface:

interface FormProvide {
  register: (item: {
    id: number | string
    validate: () => Promise<string[]>
    reset: () => void
    resetValidation: () => void
  }) => void
  unregister: (id: number | string) => void
  update: (id: number | string, isValid: boolean | null, errorMessages: string[]) => void
  items: Ref<FormField[]>
  isDisabled: ComputedRef<boolean>
  isReadonly: ComputedRef<boolean>
  isValidating: Ref<boolean>
  validateOn: Ref<FormProps['validateOn']>
}

And then in your component (from vuetify/lib/composables/validation):

  const isDisabled = computed(() => !!(props.disabled || form != null && form.isDisabled.value));

In Vuetify for Vue 2, the whole form object is provided as "form", so this should work (I don't have a vue2 project to test it):

export default {
  inject: ['form'],
  created() {
    console.log(this.form)
  }
}

CodePudding user response:

One workaround for this problem statement is to use global mixin, which will be applied to every Vue instance without explicitly passing as a prop for each and every child component.

As formDisabled is a read only property for each child, Here is the live demo :

Note : Just for a demo purpose, I am demoing it in a pure Vue format, but you can modify it as per vuetify components and test.

// This is a global mixin, it is applied to every vue instance. 
// Mixins must be instantiated *before* your call to new Vue(...)
Vue.mixin({
  data: function() {
    return {
      get formDisabled() {
        return true;
      }
    }
  }
})

Vue.component('child', {
  template: '<input type="text" :disabled="formDisabled"/>'
});

new Vue({
  el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
  <form :disabled="formDisabled">
    <child></child>
  </form>
</div>

  • Related