brutusin / json-forms

JSON Schema to HTML form generator, supporting dynamic subschemas (on the fly resolution). Extensible and customizable library with zero dependencies. Bootstrap add-ons provided
http://brutusin.org/json-forms
Apache License 2.0
608 stars 168 forks source link

Use json-forms to generate its schemas? #96

Open ouyangde opened 6 years ago

ouyangde commented 6 years ago

In order to ensure that json-forms can generate any form I desired, I tried to write a schema which can generate itself, but failed. Here is my schema:

{
    "$schema": "http://json-schema.org/draft-03/schema#",
    "type": "object",
    "properties": {
        "$schema": {
            "type": "string",
            "title": "schema",
            "description": "",
            "default": "http://json-schema.org/draft-03/schema#",
            "readOnly": true,
            "required": true
        },
        "type": {
            "type": "string",
            "title": "type",
            "default": "object",
            "readOnly": true
        },
        "properties": {
            "type": "object",
            "title": "properties",
            "additionalProperties": {
                "type": "object",
                "properties":  {
                    "type": {
                        "type": "string",
                        "enum": ["integer","string","array","object","boolean"]
                    },
                    "title": {
                        "type":"string"
                    },
                    "description": {
                        "type":"string"
                    },
                    "default": {
                        "dependsOn": [ "type" ]
                    },
                    "required": {
                        "type":"boolean"
                    },
                    "enum": {
                        "dependsOn": [ "type" ]
                    }
                }
            }
        }
    }
}

Here is my resolver function:

function resolver(names, data, cb) {
  var schemas = new Object();

  for(var key in data.properties) {
    var type = data.properties[key].type;
    if (type == 'integer' || type == 'string') {
      var schema = new Object();
      schema.type = type;
      schemas["$.properties[*].default"] = schema;
      var schema = new Object();
      schema.type = 'array';
      schema.items = {type:type};
      schemas["$.properties[*].enum"] = schema;
    }
    break;
  }  
  setTimeout(function(){cb(schemas)},500); // in order to show asynchrony
}  

I encounter two problems here.

  1. There is no way to distinguish instances of additionalProperties, since they are all marked by *.
  2. I add the first property, and change option to triger my resolver function, it's OK. But subsequent add will fail with Cannot read property 'type' of undefined
idelvall commented 6 years ago

It can't be done this way. Think the resolver as a way of getting from a valid JSON schema to an other, depending on the actual value of the JSON instance. So the problem here is that there is no a valid JSON schema that can describe these different types per additional property.

What you can do is refactor your schema to get a conceptually equivalent schema, like for example:

Since this schemas would generate JSON instances with a structure different than your actual one, and in the case you would need to maintain the actual one, you could easily perform a transformation in javascript from the generated data.