vue-formulate icon indicating copy to clipboard operation
vue-formulate copied to clipboard

Can you use v-if's using the schema generator.

Open jamessan85 opened this issue 5 years ago • 20 comments

Is it possible to use v-if's when generating forms with the schema.

Obviously you can use something like below if you were using the templates but ideally would prefer to be able to use it with the schema generator <template> <FormulateInput v-if="foo" type="text" v-model="myModel" /> </template>

jamessan85 avatar Aug 27 '20 13:08 jamessan85

The schema itself is reactive, so the recommendation is to use something like a computed function to add/remove/filter any fields you'd like to manipulate conditionally. The tricky thing about schemas is we need to be able to represent them in simple JSON format, and obviously expressions are not supported in JSON.

So for now, manipulate the schema itself conditionally. If anyone things up a good way to represent conditional logic in json format, im all ears 👍

justin-schroeder avatar Aug 27 '20 14:08 justin-schroeder

Marking this as stale for now. If future users determine this to be particularly useful or someone has a good way to represent these conditionals in json I would be happy to re-open it.

justin-schroeder avatar Sep 12 '20 02:09 justin-schroeder

How about JSONLogic as a means of declaratively defining rules in schema?

Logic

{"if" : [
  {"<": [{"var":"temp"}, 0] }, "freezing",
  {"<": [{"var":"temp"}, 100] }, "liquid",
  "gas"
]}

Data

{"temp":55}

Result

"liquid"

davidebigpicture avatar Mar 04 '21 17:03 davidebigpicture

interesting idea @davidebigpicture. It's worth considering. I'll look into the best ways to do this.

justin-schroeder avatar Mar 10 '21 15:03 justin-schroeder

I too would like to do this, as we want to use this library to allow our client to be able to dynamically create forms and use conditional questions based on prior responses.

I think the JSONLogic idea from @davidebigpicture has good merit and could be a potential solution

TL;DR +1 for this feature

EDIT: Any way we can re-open this issue?

wh1337 avatar Mar 10 '21 23:03 wh1337

I would also love this feature! Im also trying to use vue formulate for user created surveys, which must support conditional logic in the schema. A side question, is VF the best tool to use when making a user created survey app (using a custom visual drag-and-drop style survey builder which produces the schema), and then presenting these forms?

veritymedia avatar Apr 14 '21 13:04 veritymedia

Assay of Conditionals in Other Libraries

vue-form-json-schema

Has a [very verbose] way of handling this: Dynamic Options Example on Code Sandbox

       "component": "div",
        "model": "age",
        "errorHandler": true,
        "displayOptions": {
          "model": "age",
          "schema": {
            "not": {
              "type": "number"
            }
          }
        },
        "fieldOptions": {
          "class": [
            "alert alert-danger"
          ]
        },
        "children": [
          {
            "component": "div",
            "fieldOptions": {
              "domProps": {
                "innerHTML": "This field is required"
              }
            }
          }
        ]
      }

Blitzar BlitzForm

A newer form generation library that puts expressions in the JSON: Docs: Dynamic Prop Based on the Value of Another Field

  {
    id: 'under18',
    component: 'input',
    type: 'checkbox',
    defaultValue: false,
    label: 'Are you under 18?',
  },
  {
    id: 'parentalConsent',
    component: 'input',
    type: 'checkbox',
    defaultValue: false,
    label: 'Do you have parental consent?',
    subLabel: 'Only applicable when under 18',
    evaluatedProps: ['disabled'],
    // component props:
    disabled: (val, { formData }) => !formData.under18,
  },

and right after that: Show or Hide a Field Based on Another Field

  {
    id: 'car',
    component: 'input',
    type: 'checkbox',
    defaultValue: false,
    label: 'Do you have a car?',
  },
  {
    id: 'carType',
    component: 'input',
    label: 'What is the brand?',
    subLabel: 'This is only shown when the first question is `true`.',
    evaluatedProps: ['showCondition'],
    showCondition: (val, { formData }) => formData.car,
  },

FormVueLate

Doesn't bring any form field components, but has validator plugins, schema, form model, etc. Docs: Conditionally displaying an element within the schema codesandbox

  type: {
    component: FormSelect,
    label: "Schema A or B?",
    options: ["A", "B"],
  },
  aField: {
    component: FormText,
    label: "A field",
    condition: model => model.type === 'A'
  },
  bField: {
    component: FormText,
    label: 'B field',
    condition(model) {
      return model.type === 'B'
    }
  }

NCForm

Uses the concept of "dx expressions" disabled: 'dx: {{$root.person.age}} < 18'

vjsf

Conditional content using valid json, to create a "pseudo language" with if/else/then.

      "properties": {
        "booleanConditionProp": {
          "type": "boolean",
          "x-display": "switch",
          "title": "I'm a boolean used to toggle the content below"
        }
      },
      "if": {
        "required": [
          "booleanConditionProp"
        ],
        "properties": {
          "booleanConditionProp": {
            "const": true
          }
        }
      },
      "then": {
        "properties": {
          "stringProp1": {
            "type": "string",
            "title": "I'm a string available if the boolean switch is true"
          }
        }
      }

VueJS Generators

Another pretty limited library, but they are also putting expression in the JSON, for better or worse, for visible, disabled, readonly and featured(?) proeprties: Docs: Dynamic Visibility

  visible: function(model) {
    //visible if business is selected
    return model && model.type == "business";
  }

Alpaca Forms

This doesn't use Vue but it's an oldie that I thought I'd include. I'll probably find some React-forms libraries' examples later too. Alpaca uses JSON Schema Dependencies. Docs: Alpaca Conditional Dependencies Docs: Alpaca Dependencies Docs: JSON Schema Dependencies

"schema": {
        "title": "Survey",
        "type": "object",
        "properties": {
            "fan": {
                "title": "Are you an Ice Cream fanatic?",
                "type": "string",
                "enum": ["Yes", "No", "Maybe"]
            },
            "icecream": {
                "title": "I see... so what is your favorite flavor?",
                "type": "String",
                "enum": ["Vanilla", "Chocolate", "Coffee", "Strawberry", "Mint"]
            }
        },
        "dependencies": {
            "icecream": ["fan"]
        }
},
    "options": {
        "fields": {
            "fan": {
                "removeDefaultNone": true,
            },
            "icecream": {
                "dependencies": {
                    "fan": ["Yes", "Maybe"]
                }
            }
        },

The dependency is set on the triggered (shown/hidden) field, referencing the triggering field. The dependencies for enumerables appear to require setting the dependency in the schema of the fields as well as in the options.

It also appears they don't support "if date is between", "if this field is X and that other field is Y". They just support "show this field if this other field(s) values are ...."


Hope these help and spark some ideas and discussion!

Vue Formulate is the best library I've found for flexibility of custom components, validation, plugins, lack of verbosity, and thoughtfulness. I want schema-based form generation to be a first-class citizen. Our forms' definitions are stored in a database, so they're all dynamic, so the template options don't work for us. By virtue of a URL, I need to dynamically load the right form definition from the server: no hand-crafting form templates.

Inspections: "Does this facility perform surgery?" : then show a bunch of surgery questions about surgery.

Medical Doctor License Applications: "Felony record in the past year?" " then require/display fields asking for explanation and upload documents.

Employment History: Repeater groups of fields for unlimited history. If gap in dates > 6 months: then ask for explanation. ...

eyleron avatar Apr 19 '21 21:04 eyleron

hey @eyleron , thanks for this insightful information. I was wondering, which library you use the most?

dheimoz avatar Apr 20 '21 10:04 dheimoz

You're welcome.

I'm not using any of them yet, except some experiments to show coworkers what a stringified representation of some of our forms would look like so I can get buy-in.

It's chilling to come across what were once enthusiastically supported libraries that are now not maintained.

I recognize it's been a lot of decisions by the Vue Formulate team to balance, between things like:

  • what to include [kitchen sink?] vs keeping it lean and let customization happen as needed.
  • focus more narrowly on just template or just schema or include both (increases the size and workload, but brings more "into the tent")
  • include form components or have people bring their own
  • provide UI scaffolding like a grid
  • validation: just enough for the 90%, or bring your own, or allow plugins to add e.g. vuelidate/vee-validate
  • pure JSON that can validate with ajv that conforms to a spec like JSON Schema, or make your own domain language that is "based on JSON"

eyleron avatar Apr 20 '21 14:04 eyleron

I appreciate all the effort and research done into this topic. I'm not promising anything...but I think the new version has some plumbing that will allow for creating something like this as a plug-in perhaps. Either way, I hear that this is valuable to people so I'll re-open at least as a placeholder.

The question to me, is how far down this path do you go. It's only a matter of time before people are gonna want a Turing-complete language written in ...json. It feels like a slippery slope to me at least 🤷‍♂️

justin-schroeder avatar Jun 03 '21 00:06 justin-schroeder

I appreciate you considering this, and I hear you on the slippery slope! You can start with required and shown/hidden dependencies, and folks will ask for more of the things they can do in templates/computed, like how in Vue conditional logic like ternaries can determine which label, color, etc. prop value is used.

Then again, look at all the great work your team has done with everything else...I suspect many of the issues are features you didn't initially anticipate, as you start off not knowing what you don't know. Maybe you draw a line, or maybe it's a "temporal line" based on what the interest is now, what the low-hanging-fruit is now, 80-20 rule, etc. And that line changes each year as capabilities, interest, and expectations change.

Since most conditionally-shown fields are probably required, maybe the highest priority is handling just showing/hiding fields based on another field's value.

Making it a plugin and making your own take on it is a good idea. It'd provide the 80% people need, with the ability to take that and fork it into their own plugin, or provide their own (like the Turing-complete language!).

(I just checked out Alpaca Forms' dependencies which I'll add to the above list).

eyleron avatar Jun 03 '21 21:06 eyleron

List of Behaviors

We can make a list of the behaviors so y'all can mull, comment and prioritize.

Show/Hide Field on Another Field(s) Value(s)

felonyYn: Have you been convicted of a felony? ( ) Yes ( ) No felonyexplain: Please explain: [ textarea ] // triggered by (felonyYn = "Y")

Show/Hide Field on Another Field(s) Truthy Expression

(see JSONLogic)

numGuests: How many guests [ number ] payNotice: Please note your ticket only includes 1 guest; you'll have to pay for each additional // triggered by (numGuests > 1)

dateExam: List the date of your last exam [ date ] examReq: You'll need to have a new exam // triggered by (current_date - dateExam > 3 years)

Show/Hide Field Group on Another Field(s) Value(s)

As above but triggering an entire group of fields like Mailing Address (if different from Physical Address)

Require/Unrequire Field on Another Field(s) Value(s)

NotifyMethodYn: Do you want to be notified by cell or email? ( ) Cell ( ) Email email: [ email ] cell: [ tel ] // required by (notifyMethodYn = "Cell")

...

eyleron avatar Jun 03 '21 21:06 eyleron

There is another product called Formly https://formly.dev/. They have something called Expression Properties, where you can access the form data and the json template and do some common actions like for e.g.

[
    {
      key: 'text',
      type: 'input',
      templateOptions: {
        label: 'Text',
        placeholder: 'Type here to see the other field become enabled...',
      },
    },
    {
      key: 'text2',
      type: 'input',
      templateOptions: {
        label: 'Hey!',
        placeholder: 'This one is disabled if there is no text in the other input',
      },
      expressionProperties: {
        'templateOptions.disabled': '!model.text',
      },
    },
  ];

or for e.g. to change the required property, the following.

[
    {
      key: 'checked',
      type: 'checkbox',
      templateOptions: {
        label: 'Required?',
      },
    },
    {
      key: 'text',
      type: 'input',
      templateOptions: {
        label: 'Moehahah',
        placeholder: 'Formly is terrific!',
      },
      validation: {
        show: true,
      },
      expressionProperties: {
        'templateOptions.required': 'model.checked',
      },
    },
  ];

So they will have something that will cover common actions but also events e.g. on click etc.

One could make that available in the Context Object

See the following link where the previous version (Angular 1) where Expressions are explained. http://docs.angular-formly.com/docs/formly-expressions

andyfensham avatar Aug 04 '21 18:08 andyfensham

Interesting. It definitely seems it is a bit of a wild west out there, but I'm sure we can come up with something really solid. Thanks for the feature lists @eyleron and this example too @andyfensham

justin-schroeder avatar Aug 04 '21 18:08 justin-schroeder

Will this be supported in the new FormKit package?

hisuwh avatar Dec 08 '21 14:12 hisuwh

Very much so. FormKit uses a nearly Turing complete schema :)

justin-schroeder avatar Dec 08 '21 14:12 justin-schroeder

Yes, @hisuwh! FormKit schema is a first-class citizen and the Alpha already supports boolean logic, comparison, and arithmetic expressions, conditional rendering, loops, and dynamic data as well.

luan-nk-nguyen avatar Dec 08 '21 14:12 luan-nk-nguyen

Sounds kl. Is the beta still planned for "late 2021" - I applied so hopefully I get a seat. Not much of 2021 left though

hisuwh avatar Dec 08 '21 14:12 hisuwh

Yes indeed @hisuwh. The private Beta opens in about 1 week.

luan-nk-nguyen avatar Dec 08 '21 15:12 luan-nk-nguyen

excited!

hisuwh avatar Dec 08 '21 17:12 hisuwh