Open jamessan85 opened 3 years ago
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 👍
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.
How about JSONLogic as a means of declaratively defining rules in schema?
{"if" : [
{"<": [{"var":"temp"}, 0] }, "freezing",
{"<": [{"var":"temp"}, 100] }, "liquid",
"gas"
]}
{"temp":55}
"liquid"
interesting idea @davidebigpicture. It's worth considering. I'll look into the best ways to do this.
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?
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?
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"
}
}
}
]
}
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,
},
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'
}
}
Uses the concept of "dx expressions" disabled: 'dx: {{$root.person.age}} < 18'
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"
}
}
}
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";
}
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. ...
hey @eyleron , thanks for this insightful information. I was wondering, which library you use the most?
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:
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 🤷♂️
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).
We can make a list of the behaviors so y'all can mull, comment and prioritize.
felonyYn: Have you been convicted of a felony? ( ) Yes ( ) No felonyexplain: Please explain: [ textarea ] // triggered by (felonyYn = "Y")
(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)
As above but triggering an entire group of fields like Mailing Address (if different from Physical Address)
NotifyMethodYn: Do you want to be notified by cell or email? ( ) Cell ( ) Email email: [ email ] cell: [ tel ] // required by (notifyMethodYn = "Cell")
...
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
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
Will this be supported in the new FormKit package?
Very much so. FormKit uses a nearly Turing complete schema :)
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.
Sounds kl. Is the beta still planned for "late 2021" - I applied so hopefully I get a seat. Not much of 2021 left though
Yes indeed @hisuwh. The private Beta opens in about 1 week.
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>