diff --git a/docs/api.md b/docs/api.md index 0c60ea7..4bca237 100644 --- a/docs/api.md +++ b/docs/api.md @@ -102,6 +102,11 @@ Constructs a new JSONEditor. See [http://json-schema.org/](http://json-schema.org/) for more information. +- `{Object} schemaRefs` + + Schemas that are referenced using the `$ref` property from the JSON schema that are set in the `schema` option, + the object structure in the form of `{reference_key: schemaObject}` + - `{boolean} search` Enables a search box in the upper right corner of the JSONEditor. True by default. Only applicable when `mode` is 'tree', 'view', or 'form'. @@ -234,6 +239,20 @@ See [http://json-schema.org/](http://json-schema.org/) for more information on t A JSON schema. +#### `JSONEditor.setSchemaRef(schema, ref)` + +Set a schema that are referenced from the schema that are set on the `schema` option. See also option `schemaRefs`. + +*Parameters:* + +- `{Object} schema` + + A JSON schema. + +- `{String} ref` + + The reference key. + #### `JSONEditor.setText(jsonString)` Set text data in the editor. diff --git a/examples/07_json_schema_validation.html b/examples/07_json_schema_validation.html index 8338b67..e54e3b4 100644 --- a/examples/07_json_schema_validation.html +++ b/examples/07_json_schema_validation.html @@ -47,20 +47,41 @@ "description": "Age in years", "type": "integer", "minimum": 0 + }, + "job": { + "$ref": "job" } }, "required": ["firstName", "lastName"] }; + var job = { + "title": "Job description", + "type": "object", + "properties": { + "company": { + "type": "string" + }, + "role": { + "type": "string" + } + } + }; + var json = { firstName: 'John', lastName: 'Doe', gender: null, - age: 28 + age: 28, + job: { + company: 'freelance', + role: 'developer' + } }; var options = { - schema: schema + schema: schema, + schemaRefs: {"job": job} }; // create the editor diff --git a/src/js/JSONEditor.js b/src/js/JSONEditor.js index 1cc6788..5b48336 100644 --- a/src/js/JSONEditor.js +++ b/src/js/JSONEditor.js @@ -79,7 +79,7 @@ function JSONEditor (container, options, json) { // validate options if (options) { var VALID_OPTIONS = [ - 'ajv', 'schema','templates', + 'ajv', 'schema', 'schemaRefs','templates', 'ace', 'theme','autocomplete', 'onChange', 'onEditable', 'onError', 'onModeChange', 'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys' @@ -269,6 +269,40 @@ JSONEditor.prototype._onError = function(err) { } }; +/** + * Returns ajv instance, initiates if not exists + * @returns {Object} ajv + */ +JSONEditor.prototype._getAjvInstance = function () { + if (!this.ajv) { + try { + // grab ajv from options if provided, else create a new instance + this.ajv = this.options.ajv || Ajv({ allErrors: true, verbose: true }); + + } + catch (err) { + console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.'); + } + } + return this.ajv; +}; + +/** + * Set reference schema object for schema which is depended with other schemas using
$ref
+ * @param {Object} schema Schema object + * @param {String} ref reference key + */ +JSONEditor.prototype.setSchemaRef = function (schema, ref) { + if (schema && ref) { + var ajv = this._getAjvInstance(); + + if (ajv) { + ajv.removeSchema(ref); + ajv.addSchema(schema, ref); + } + } +}; + /** * Set a JSON schema for validation of the JSON object. * To remove the schema, call JSONEditor.setSchema(null) @@ -277,15 +311,7 @@ JSONEditor.prototype._onError = function(err) { JSONEditor.prototype.setSchema = function (schema) { // compile a JSON schema validator if a JSON schema is provided if (schema) { - var ajv; - try { - // grab ajv from options if provided, else create a new instance - ajv = this.options.ajv || Ajv({ allErrors: true, verbose: true }); - - } - catch (err) { - console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.'); - } + var ajv = this._getAjvInstance(); if (ajv) { this.validateSchema = ajv.compile(schema); diff --git a/src/js/textmode.js b/src/js/textmode.js index 7076fde..3c3fd0d 100644 --- a/src/js/textmode.js +++ b/src/js/textmode.js @@ -220,6 +220,12 @@ textmode.create = function (container, options) { } } + if (this.options.schemaRefs) { + for (var ref in this.options.schemaRefs) { + this.setSchemaRef(this.options.schemaRefs[ref], ref); + } + } + this.setSchema(this.options.schema); }; diff --git a/src/js/treemode.js b/src/js/treemode.js index d3737b4..7aca5b3 100644 --- a/src/js/treemode.js +++ b/src/js/treemode.js @@ -112,6 +112,7 @@ treemode._setOptions = function (options) { mode: 'tree', name: undefined, // field name of root node schema: null, + schemaRefs: null, autocomplete: null }; @@ -124,6 +125,13 @@ treemode._setOptions = function (options) { } } + // set schema refs before schema compile, is available + if (this.options.schemaRefs) { + for (var ref in this.options.schemaRefs) { + this.setSchemaRef(this.options.schemaRefs[ref], ref); + } + } + // compile a JSON schema validator if a JSON schema is provided this.setSchema(this.options.schema); diff --git a/test/test_schema.html b/test/test_schema.html index 4b60562..56d284f 100644 --- a/test/test_schema.html +++ b/test/test_schema.html @@ -57,22 +57,27 @@ "minimum": 0 }, "hobbies": { - "type": "array", - "items": { - "type": "string" - } + "$ref": "hobbies.json" } }, "required": ["firstName", "lastName"] }; + var hobbiesSchema = { + "type": "array", + "items": { + "type": "string" + } + }; + var options = { mode: 'tree', modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes onError: function (err) { console.error(err); }, - schema: schema + schema: schema, + schemaRefs: {"hobbies.json": hobbiesSchema} }; var json = {