Limenius / liform-react

Generate forms from JSON Schema to use with React (& redux-form)
https://limenius.github.io/liform-react/
MIT License
174 stars 42 forks source link

Support dynamic forms via dependencies #17

Open mfulton26 opened 7 years ago

mfulton26 commented 7 years ago

It would be great if we could generate forms with conditionally required and conditionally present fields.

Property dependencies examples

In the following JSON Schema the form contains several fields and if the user enters anything into the "credit_card" field then the "billing_address" field becomes required, otherwise it remains optional.

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "credit_card": { "type": "number" },
    "billing_address": { "type": "string" }
  },
  "required": ["name"],
  "dependencies": {
    "credit_card": ["billing_address"]
  }
}

Bidirectional dependencies could also be used; here the same fields are displayed but if the user enters anything into either "credit_card" or "billing_address" then they both become required.

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "credit_card": { "type": "number" },
    "billing_address": { "type": "string" }
  },
  "required": ["name"],
  "dependencies": {
    "credit_card": ["billing_address"],
    "billing_address": ["credit_card"]
  }
}

Schema dependencies examples

In the following example the form initially only has the "name" (required) and "credit_card" (optional) fields but if the user enters something into the "credit_card" field then a new field is added to the form: "billing_address" (required).

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "credit_card": { "type": "number" }
  },
  "required": ["name"],
  "dependencies": {
    "credit_card": {
      "properties": {
        "billing_address": { "type": "string" }
      },
      "required": ["billing_address"]
    }
  }
}

The above examples were taken from Dependencies — object — Understanding JSON Schema 1.0 documentation.

Here is a more complex example of my own making: Here the potential power of dependencies really shines as the user can add multiple persons to the form, for each person they add their name and are then asked a single question and depending on the answer to that question an additional question may be asked specific to the specified answer for the specific person.

{
    "title": "Persons",
    "type": "array",
    "items": {
        "title": "Person",
        "type": "object",
        "properties": {
            "Name": {
                "type": "string"
            },
            "Do you have any pets?": {
                "type": "string",
                "enum": ["No", "Yes: One", "Yes: More than one"]
            }
        },
        "required": ["Name", "Do you have any pets?"],
        "dependencies": {
            "Do you have any pets?": {
                "oneOf": [
                    {
                        "properties": {
                            "Do you have any pets?": {
                                "enum": ["No"]
                            }
                        }
                    },
                    {
                        "properties": {
                            "Do you have any pets?": {
                                "enum": ["Yes: One"]
                            },
                            "How old is your pet?": {
                                "type": "number"
                            }
                        },
                        "required": ["How old is your pet?"]
                    },
                    {
                        "properties": {
                            "Do you have any pets?": {
                                "enum": ["Yes: More than one"]
                            },
                            "How old is your oldest pet?": {
                                "type": "number"
                            }
                        },
                        "required": ["How old is your oldest pet?"]
                    }
                ]
            }
        }
    }
}

I would find being able to define a dynamic form using dependencies extremely beneficial as complex forms would be able to succinctly define in declarative JSON Schema their forms and perform server-side validation for submitted data using the same schemas.

Note; There is a lot here. I hope it isn't too overwhelming. I would suggest starting small by adding property dependencies support only and then slowly adding additional support for simpler to more complex schema dependencies.

handrews commented 6 years ago

Note that as of draft-07 there are other mechanisms, per #40 in this repo.

In draft-08, dependencies will split- the schema form used here will (almost certainly) still be called dependencies, while the string array form will get a new name (probably dependentRequired, as it is a shorthand for conditional required arrays).

I'd recommend focusing on the newer keywords for this sort of thing where possible.