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
546 stars 155 forks source link

Conditional schema is very limited. Need workaround. #273

Closed DavidPodi closed 1 month ago

DavidPodi commented 3 years ago

I tried the conditional schemas, but from what I can see it looks like once I add a condition then I need to split my schemas which means I can't access the other schema with a property from the first schema or I am limited with the order of my properties.

For example, if I want to keep this property order and hide conditionalProp1 based on showOrHideProp1 and then conditionalProp2 based on showOrHideProp2, there doesn't seem to be a way to do this:

properties: {

   showOrHideProp1: { type: bool },
   showOrHideProp2: { type: bool },
   regularProp: { type: string },
   conditionalProp1: { type: string },
   conditionalProp2: { type: string },
   finalProp: { type: string },
} 

I can use conditional schema to apply this condition for the first condition:

"allOf": [
   {
   properties: {
      showOrHideProp1: { type: bool}
      showOrHideProp2: { type: bool},
      regularProp: { type: string}
   },
   if: {...showOrHideProp1}
   then: {...condtionalProp1}
   else: {...}
   },
  properties: {
     conditionalProp2: { type: string } /// Propblem here
     finalProp: { type: string }
  }
]

Now I have no way to hide conditionalProp2 based on showOrHideProp2 because they are in two different schemas.

Is there any other way to do this and keep the property order?

DavidPodi commented 3 years ago

As a workaround I am rendering the input using another instance of v-jsf and then evaluating an expression with an attribute I made up "x-show-expression":


            <template slot="custom-component" slot-scope="context">
              <v-jsf v-show="evaluateExpression(context, 'x-show-expression')" :disabled="context.disabled" :required="context.required" :rules="context.rules" :value="context.value" :schema="JSON.parse(JSON.stringify(context.schema))" :options="options" @input="context.on.input" @change="context.on.change" >
              </v-jsf>
            </template>
 "conditionalProp2": {
                  "type": "string",
                  "x-display": "custom-component",
                  "x-tag": "v-textarea",
                  "x-show-expression": "this.model.showOrHideProp2 === true"
                }
    evaluateExpression: function (context, property) {
      if (context.schema[property]) {
        return eval(context.schema[property]);
      } else {
        return true;
      }
    }

I'm not sure if I'm going to run into problems doing this, but this way I can control when to display the property with an expression. Obviously, this is not following the json schema way to do things, but since it is so limited, it would be great if you could expose an event or have a supported way to allow us to custom render and extend the vjsf input so we can use our own expressions without having to write a new component for each input.

albanm commented 3 years ago

Yes this whole subject is not easy and there is a lot of room for improvement.

There is an undocumented "x-if" annotation. It uses the same mechanism as x-fromData for selects, you can watch a property either in options.context or the model. But it is limited, it only checks if the value found at this key is truthy, it does not evaluate an expression.

I don't know how we could have more useful expressions. The nice thing with the if/then/else syntax is that json-schema itself is the expression language, but I agree that it is not really usable in many cases.

Meplos commented 2 years ago

Hey, I work on a PR which improve x-if annotation using expr-eval package. I just wan't to be sure is good for you

albanm commented 2 years ago

I'm ok with that. Please include in the PR extending this part of the documentation https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/configuration/#expressions and probably also this example https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/examples#_x-if

Also I would prefer not to add the package as a required dependency and only try to use it if the "evalMethod" option asks for it.

Meplos commented 2 years ago

I add a Expression mixin to configure the parser. How can I use it dynamically with the eval method property?