From 2072fca7a448e18f73cfc219ade51768ebc4ebd6 Mon Sep 17 00:00:00 2001 From: Chase Sterling Date: Thu, 6 Aug 2015 01:31:42 -0400 Subject: [PATCH 1/7] Extend traverseSchema utility to recurse into other types of nested schemas Add some other utility functions to help manipulate schemas --- src/services/schema-form.js | 95 ++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/src/services/schema-form.js b/src/services/schema-form.js index feaec7293..e420df64d 100644 --- a/src/services/schema-form.js +++ b/src/services/schema-form.js @@ -434,7 +434,6 @@ angular.module('schemaForm').provider('schemaForm', path = path || []; var traverse = function(schema, fn, path) { - fn(schema, path); angular.forEach(schema.properties, function(prop, name) { var currentPath = path.slice(); currentPath.push(name); @@ -446,11 +445,105 @@ angular.module('schemaForm').provider('schemaForm', var arrPath = path.slice(); arrPath.push(''); traverse(schema.items, fn, arrPath); } + if (schema.dependencies) { + angular.forEach(schema.dependencies, function(value, key) { + if(typeof value === "object" && !(Array.isArray(value))) { + traverse(value, fn, path); + } + }); + } + if (schema.not) { + traverse(schema.not, fn, path) + } + angular.forEach(['allOf', 'oneOf', 'anyOf'], function(prop) { + if (schema[prop]) { + angular.forEach(schema[prop], function(value) { + traverse(value, fn, path); + }) + } + }); + fn(schema, path); }; traverse(schema, fn, path || []); }; + service.expandSchema = function(schema) { + + service.traverseSchema(schema, function(schema) { + // allOf schemas should be merged into the parent + if(schema.allOf) { + for(i=0; i Date: Thu, 6 Aug 2015 01:33:14 -0400 Subject: [PATCH 2/7] Start some work on a schemaSelector directive --- src/directives/schema-selector.js | 238 ++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 src/directives/schema-selector.js diff --git a/src/directives/schema-selector.js b/src/directives/schema-selector.js new file mode 100644 index 000000000..b10aaf777 --- /dev/null +++ b/src/directives/schema-selector.js @@ -0,0 +1,238 @@ +/** + * Directive that handles a choice of schemas + */ +angular.module('schemaForm').directive('sfSchemaSelector', ['sfSelect', 'schemaForm', 'sfValidator', 'sfPath', + function(sfSelect, schemaForm, sfValidator, sfPath) { + + return { + restrict: 'A', + scope: true, + require: '?ngModel', + link: function(scope, element, attrs, ngModel) { + var formDefCache = {}; + + scope.validateSchemaSelector = angular.noop; + + if (ngModel) { + // We need the ngModelController on several places, + // most notably for errors. + // So we emit it up to the decorator directive so it can put it on scope. + scope.$emit('schemaFormPropagateNgModelController', ngModel); + } + + + // Watch for the form definition and then rewrite it. + // It's the (first) array part of the key, '[]' that needs a number + // corresponding to an index of the form. + var once = scope.$watch(attrs.sfArray, function(form) { + if (!form) { + return; + } + + + // An array model always needs a key so we know what part of the model + // to look at. This makes us a bit incompatible with JSON Form, on the + // other hand it enables two way binding. + var list = sfSelect(form.key, scope.model); + + // We only modify the same array instance but someone might change the array from + // the outside so let's watch for that. We use an ordinary watch since the only case + // we're really interested in is if its a new instance. + var key = sfPath.normalize(form.key); + scope.$watch('model' + (key[0] !== '[' ? '.' : '') + key, function(value) { + list = scope.modelArray = value; + }); + + // Since ng-model happily creates objects in a deep path when setting a + // a value but not arrays we need to create the array. + if (angular.isUndefined(list)) { + list = []; + sfSelect(form.key, scope.model, list); + } + scope.modelArray = list; + + // Arrays with titleMaps, i.e. checkboxes doesn't have items. + if (form.items) { + + // To be more compatible with JSON Form we support an array of items + // in the form definition of "array" (the schema just a value). + // for the subforms code to work this means we wrap everything in a + // section. Unless there is just one. + var subForm = form.items[0]; + if (form.items.length > 1) { + subForm = { + type: 'section', + items: form.items.map(function(item) { + item.ngModelOptions = form.ngModelOptions; + if (angular.isUndefined(item.readonly)) { + item.readonly = form.readonly; + } + return item; + }) + }; + } + + } + + scope.appendToArray = function() { + var len = list.length; + var copy = scope.copyWithIndex(len); + schemaForm.traverseForm(copy, function(part) { + + if (part.key) { + var def; + if (angular.isDefined(part['default'])) { + def = part['default']; + } + if (angular.isDefined(part.schema) && + angular.isDefined(part.schema['default'])) { + def = part.schema['default']; + } + + if (angular.isDefined(def)) { + sfSelect(part.key, scope.model, def); + } + } + }); + + // If there are no defaults nothing is added so we need to initialize + // the array. undefined for basic values, {} or [] for the others. + if (len === list.length) { + var type = sfSelect('schema.items.type', form); + var dflt; + if (type === 'object') { + dflt = {}; + } else if (type === 'array') { + dflt = []; + } + list.push(dflt); + } + + // Trigger validation. + scope.validateSchemaSelector(); + return list; + }; + + scope.deleteFromArray = function(index) { + list.splice(index, 1); + + // Trigger validation. + scope.validateSchemaSelector(); + + // Angular 1.2 lacks setDirty + if (ngModel && ngModel.$setDirty) { + ngModel.$setDirty(); + } + return list; + }; + + // Always start with one empty form unless configured otherwise. + // Special case: don't do it if form has a titleMap + if (!form.titleMap && form.startEmpty !== true && list.length === 0) { + scope.appendToArray(); + } + + // Title Map handling + // If form has a titleMap configured we'd like to enable looping over + // titleMap instead of modelArray, this is used for intance in + // checkboxes. So instead of variable number of things we like to create + // a array value from a subset of values in the titleMap. + // The problem here is that ng-model on a checkbox doesn't really map to + // a list of values. This is here to fix that. + if (form.titleMap && form.titleMap.length > 0) { + scope.titleMapValues = []; + + // We watch the model for changes and the titleMapValues to reflect + // the modelArray + var updateTitleMapValues = function(arr) { + scope.titleMapValues = []; + arr = arr || []; + + form.titleMap.forEach(function(item) { + scope.titleMapValues.push(arr.indexOf(item.value) !== -1); + }); + }; + //Catch default values + updateTitleMapValues(scope.modelArray); + scope.$watchCollection('modelArray', updateTitleMapValues); + + //To get two way binding we also watch our titleMapValues + scope.$watchCollection('titleMapValues', function(vals, old) { + if (vals && vals !== old) { + var arr = scope.modelArray; + + // Apparently the fastest way to clear an array, readable too. + // http://jsperf.com/array-destroy/32 + while (arr.length > 0) { + arr.pop(); + } + form.titleMap.forEach(function(item, index) { + if (vals[index]) { + arr.push(item.value); + } + }); + + // Time to validate the rebuilt array. + scope.validateSchemaSelector(); + } + }); + } + + // If there is a ngModel present we need to validate when asked. + if (ngModel) { + var error; + + scope.validateSchemaSelector = function() { + // The actual content of the array is validated by each field + // so we settle for checking validations specific to arrays + + // Since we prefill with empty arrays we can get the funny situation + // where the array is required but empty in the gui but still validates. + // Thats why we check the length. + var result = sfValidator.validate( + form, + scope.modelArray.length > 0 ? scope.modelArray : undefined + ); + + // TODO: DRY this up, it has a lot of similarities with schema-validate + // Since we might have different tv4 errors we must clear all + // errors that start with tv4- + Object.keys(ngModel.$error) + .filter(function(k) { return k.indexOf('tv4-') === 0; }) + .forEach(function(k) { ngModel.$setValidity(k, true); }); + + if (result.valid === false && + result.error && + (result.error.dataPath === '' || + result.error.dataPath === '/' + form.key[form.key.length - 1])) { + + // Set viewValue to trigger $dirty on field. If someone knows a + // a better way to do it please tell. + ngModel.$setViewValue(scope.modelArray); + error = result.error; + ngModel.$setValidity('tv4-' + result.error.code, false); + } + }; + + scope.$on('schemaFormValidate', scope.validateSchemaSelector); + + scope.hasSuccess = function() { + return ngModel.$valid && !ngModel.$pristine; + }; + + scope.hasError = function() { + return ngModel.$invalid; + }; + + scope.schemaError = function() { + return error; + }; + + } + + once(); + }); + } + }; + } +]); From c01317080660d7421a8083c9659656810779ad82 Mon Sep 17 00:00:00 2001 From: Chase Sterling Date: Mon, 10 Aug 2015 02:09:05 -0400 Subject: [PATCH 3/7] Start some work on a formselect type --- .../bootstrap/bootstrap-decorator.js | 1 + .../decorators/bootstrap/formselect.html | 10 ++ src/services/schema-form.js | 169 +++++++++++------- 3 files changed, 112 insertions(+), 68 deletions(-) create mode 100644 src/directives/decorators/bootstrap/formselect.html diff --git a/src/directives/decorators/bootstrap/bootstrap-decorator.js b/src/directives/decorators/bootstrap/bootstrap-decorator.js index 4f0d5bb7e..658cb7fa4 100644 --- a/src/directives/decorators/bootstrap/bootstrap-decorator.js +++ b/src/directives/decorators/bootstrap/bootstrap-decorator.js @@ -9,6 +9,7 @@ angular.module('schemaForm').config(['schemaFormDecoratorsProvider', function(de console.log('fieldset children frag', children.childNodes) args.fieldFrag.childNode.appendChild(children); }},*/ + formselect: {template: base + 'formselect.html', replace: false}, array: {template: base + 'array.html', replace: false}, tabarray: {template: base + 'tabarray.html', replace: false}, tabs: {template: base + 'tabs.html', replace: false}, diff --git a/src/directives/decorators/bootstrap/formselect.html b/src/directives/decorators/bootstrap/formselect.html new file mode 100644 index 000000000..6b9fdcf5f --- /dev/null +++ b/src/directives/decorators/bootstrap/formselect.html @@ -0,0 +1,10 @@ +
+ {{ form.title }} +
+ + +
diff --git a/src/services/schema-form.js b/src/services/schema-form.js index e420df64d..08dd43328 100644 --- a/src/services/schema-form.js +++ b/src/services/schema-form.js @@ -6,14 +6,16 @@ angular.module('schemaForm').provider('schemaForm', ['sfPathProvider', function(sfPathProvider) { var stripNullType = function(type) { - if (Array.isArray(type) && type.length == 2) { - if (type[0] === 'null') - return type[1]; - if (type[1] === 'null') - return type[0]; + if (Array.isArray(type) && type.length > 1) { + var filtered = type.filter(function (type) { + return type !== 'null' + }); + if (filtered.length == 1) + return filtered[0]; + return filtered; } return type; - } + }; //Creates an default titleMap list from an enum, i.e. a list of strings. var enumToTitleMap = function(enm) { @@ -43,8 +45,71 @@ angular.module('schemaForm').provider('schemaForm', return titleMap; }; + var extendSchemas = function(obj1, obj2) { + obj1 = angular.extend({}, obj1); + obj2 = angular.extend({}, obj2); + + var self = this; + var extended = {}; + angular.forEach(obj1, function(val,prop) { + // If this key is also defined in obj2, merge them + if(typeof obj2[prop] !== 'undefined') { + // Required arrays should be unioned together + if(prop === 'required' && typeof val === 'object' && Array.isArray(val)) { + // Union arrays and unique + extended.required = val.concat(obj2[prop]).reduce(function(p, c) { + if (p.indexOf(c) < 0) p.push(c); + return p; + }, []); + } + // Type should be intersected and is either an array or string + else if(prop === 'type' && (typeof val === 'string' || Array.isArray(val))) { + // Make sure we're dealing with arrays + if(typeof val === 'string') val = [val]; + if(typeof obj2.type === 'string') obj2.type = [obj2.type]; + + + extended.type = val.filter(function(n) { + return obj2.type.indexOf(n) !== -1; + }); + + // If there's only 1 type, use a string instead of array + if(extended.type.length === 1) { + extended.type = extended.type[0]; + } + } + // All other arrays should be intersected (enum, etc.) + else if(typeof val === 'object' && Array.isArray(val)){ + extended[prop] = val.filter(function(n) { + return obj2[prop].indexOf(n) !== -1; + }); + } + // Objects should be recursively merged + else if(typeof val === 'object' && val !== null) { + extended[prop] = extendSchemas(val, obj2[prop]); + } + // Otherwise, use the first value + else { + extended[prop] = val; + } + } + // Otherwise, just use the one in obj1 + else { + extended[prop] = val; + } + }); + // Properties in obj2 that aren't in obj1 + angular.forEach(obj2, function(val, prop) { + if(typeof obj1[prop] === 'undefined') { + extended[prop] = val; + } + }); + + return extended; + }; + var defaultFormDefinition = function(name, schema, options) { - var rules = defaults[stripNullType(schema.type)]; + var rules = defaults['any'].concat(defaults[stripNullType(schema.type)]); if (rules) { var def; for (var i = 0; i < rules.length; i++) { @@ -228,9 +293,38 @@ angular.module('schemaForm').provider('schemaForm', }; + var formselect = function(name, schema, options) { + var types = stripNullType(schema.type); + if (!(schema.oneOf || schema.anyOf || angular.isArray(types))) return; + schemas = []; + var f = stdFormObj(name, schema, options); + f.type = 'formselect'; + // TODO: What if there are more than one of these keys in the same schema? + if (angular.isArray(types)) { + angular.forEach(types, function(type) { + schemas.push(extendSchemas({type: type}, schema)); + }) + } else { + angular.forEach(schema.anyOf || schema.oneOf, function(value) { + var extended = extendSchemas(value, schema); + delete extended.oneOf; + delete extended.anyOf; + schemas.push(extended) + }) + } + f.items = []; + angular.forEach(schemas, function(s) { + // TODO: Set condition for each of these forms based on selection + f.items.push(defaultFormDefinition(name, s, options)); + }); + + return f; + }; + //First sorted by schema type then a list. //Order has importance. First handler returning an form snippet will be used. var defaults = { + any: [formselect], string: [select, text], object: [fieldset], number: [number], @@ -481,68 +575,7 @@ angular.module('schemaForm').provider('schemaForm', }); }; - service.extendSchemas = function(obj1, obj2) { - obj1 = angular.extend({}, obj1); - obj2 = angular.extend({}, obj2); - - var self = this; - var extended = {}; - angular.forEach(obj1, function(val,prop) { - // If this key is also defined in obj2, merge them - if(typeof obj2[prop] !== 'undefined') { - // Required arrays should be unioned together - if(prop === 'required' && typeof val === 'object' && Array.isArray(val)) { - // Union arrays and unique - extended.required = val.concat(obj2[prop]).reduce(function(p, c) { - if (p.indexOf(c) < 0) p.push(c); - return p; - }, []); - } - // Type should be intersected and is either an array or string - else if(prop === 'type' && (typeof val === 'string' || Array.isArray(val))) { - // Make sure we're dealing with arrays - if(typeof val === 'string') val = [val]; - if(typeof obj2.type === 'string') obj2.type = [obj2.type]; - - - extended.type = val.filter(function(n) { - return obj2.type.indexOf(n) !== -1; - }); - - // If there's only 1 type, use a string instead of array - if(extended.type.length === 1) { - extended.type = extended.type[0]; - } - } - // All other arrays should be intersected (enum, etc.) - else if(typeof val === 'object' && Array.isArray(val)){ - extended[prop] = val.filter(function(n) { - return obj2[prop].indexOf(n) !== -1; - }); - } - // Objects should be recursively merged - else if(typeof val === 'object' && val !== null) { - extended[prop] = self.extendSchemas(val, obj2[prop]); - } - // Otherwise, use the first value - else { - extended[prop] = val; - } - } - // Otherwise, just use the one in obj1 - else { - extended[prop] = val; - } - }); - // Properties in obj2 that aren't in obj1 - angular.forEach(obj2, function(val, prop) { - if(typeof obj1[prop] === 'undefined') { - extended[prop] = val; - } - }); - return extended; - }; service.traverseForm = function(form, fn) { fn(form); From 15e67b750f4e3a5b512ac7752a8a9b98555257a9 Mon Sep 17 00:00:00 2001 From: Chase Sterling Date: Mon, 10 Aug 2015 02:23:08 -0400 Subject: [PATCH 4/7] Remove unused directive --- src/directives/schema-selector.js | 238 ------------------------------ 1 file changed, 238 deletions(-) delete mode 100644 src/directives/schema-selector.js diff --git a/src/directives/schema-selector.js b/src/directives/schema-selector.js deleted file mode 100644 index b10aaf777..000000000 --- a/src/directives/schema-selector.js +++ /dev/null @@ -1,238 +0,0 @@ -/** - * Directive that handles a choice of schemas - */ -angular.module('schemaForm').directive('sfSchemaSelector', ['sfSelect', 'schemaForm', 'sfValidator', 'sfPath', - function(sfSelect, schemaForm, sfValidator, sfPath) { - - return { - restrict: 'A', - scope: true, - require: '?ngModel', - link: function(scope, element, attrs, ngModel) { - var formDefCache = {}; - - scope.validateSchemaSelector = angular.noop; - - if (ngModel) { - // We need the ngModelController on several places, - // most notably for errors. - // So we emit it up to the decorator directive so it can put it on scope. - scope.$emit('schemaFormPropagateNgModelController', ngModel); - } - - - // Watch for the form definition and then rewrite it. - // It's the (first) array part of the key, '[]' that needs a number - // corresponding to an index of the form. - var once = scope.$watch(attrs.sfArray, function(form) { - if (!form) { - return; - } - - - // An array model always needs a key so we know what part of the model - // to look at. This makes us a bit incompatible with JSON Form, on the - // other hand it enables two way binding. - var list = sfSelect(form.key, scope.model); - - // We only modify the same array instance but someone might change the array from - // the outside so let's watch for that. We use an ordinary watch since the only case - // we're really interested in is if its a new instance. - var key = sfPath.normalize(form.key); - scope.$watch('model' + (key[0] !== '[' ? '.' : '') + key, function(value) { - list = scope.modelArray = value; - }); - - // Since ng-model happily creates objects in a deep path when setting a - // a value but not arrays we need to create the array. - if (angular.isUndefined(list)) { - list = []; - sfSelect(form.key, scope.model, list); - } - scope.modelArray = list; - - // Arrays with titleMaps, i.e. checkboxes doesn't have items. - if (form.items) { - - // To be more compatible with JSON Form we support an array of items - // in the form definition of "array" (the schema just a value). - // for the subforms code to work this means we wrap everything in a - // section. Unless there is just one. - var subForm = form.items[0]; - if (form.items.length > 1) { - subForm = { - type: 'section', - items: form.items.map(function(item) { - item.ngModelOptions = form.ngModelOptions; - if (angular.isUndefined(item.readonly)) { - item.readonly = form.readonly; - } - return item; - }) - }; - } - - } - - scope.appendToArray = function() { - var len = list.length; - var copy = scope.copyWithIndex(len); - schemaForm.traverseForm(copy, function(part) { - - if (part.key) { - var def; - if (angular.isDefined(part['default'])) { - def = part['default']; - } - if (angular.isDefined(part.schema) && - angular.isDefined(part.schema['default'])) { - def = part.schema['default']; - } - - if (angular.isDefined(def)) { - sfSelect(part.key, scope.model, def); - } - } - }); - - // If there are no defaults nothing is added so we need to initialize - // the array. undefined for basic values, {} or [] for the others. - if (len === list.length) { - var type = sfSelect('schema.items.type', form); - var dflt; - if (type === 'object') { - dflt = {}; - } else if (type === 'array') { - dflt = []; - } - list.push(dflt); - } - - // Trigger validation. - scope.validateSchemaSelector(); - return list; - }; - - scope.deleteFromArray = function(index) { - list.splice(index, 1); - - // Trigger validation. - scope.validateSchemaSelector(); - - // Angular 1.2 lacks setDirty - if (ngModel && ngModel.$setDirty) { - ngModel.$setDirty(); - } - return list; - }; - - // Always start with one empty form unless configured otherwise. - // Special case: don't do it if form has a titleMap - if (!form.titleMap && form.startEmpty !== true && list.length === 0) { - scope.appendToArray(); - } - - // Title Map handling - // If form has a titleMap configured we'd like to enable looping over - // titleMap instead of modelArray, this is used for intance in - // checkboxes. So instead of variable number of things we like to create - // a array value from a subset of values in the titleMap. - // The problem here is that ng-model on a checkbox doesn't really map to - // a list of values. This is here to fix that. - if (form.titleMap && form.titleMap.length > 0) { - scope.titleMapValues = []; - - // We watch the model for changes and the titleMapValues to reflect - // the modelArray - var updateTitleMapValues = function(arr) { - scope.titleMapValues = []; - arr = arr || []; - - form.titleMap.forEach(function(item) { - scope.titleMapValues.push(arr.indexOf(item.value) !== -1); - }); - }; - //Catch default values - updateTitleMapValues(scope.modelArray); - scope.$watchCollection('modelArray', updateTitleMapValues); - - //To get two way binding we also watch our titleMapValues - scope.$watchCollection('titleMapValues', function(vals, old) { - if (vals && vals !== old) { - var arr = scope.modelArray; - - // Apparently the fastest way to clear an array, readable too. - // http://jsperf.com/array-destroy/32 - while (arr.length > 0) { - arr.pop(); - } - form.titleMap.forEach(function(item, index) { - if (vals[index]) { - arr.push(item.value); - } - }); - - // Time to validate the rebuilt array. - scope.validateSchemaSelector(); - } - }); - } - - // If there is a ngModel present we need to validate when asked. - if (ngModel) { - var error; - - scope.validateSchemaSelector = function() { - // The actual content of the array is validated by each field - // so we settle for checking validations specific to arrays - - // Since we prefill with empty arrays we can get the funny situation - // where the array is required but empty in the gui but still validates. - // Thats why we check the length. - var result = sfValidator.validate( - form, - scope.modelArray.length > 0 ? scope.modelArray : undefined - ); - - // TODO: DRY this up, it has a lot of similarities with schema-validate - // Since we might have different tv4 errors we must clear all - // errors that start with tv4- - Object.keys(ngModel.$error) - .filter(function(k) { return k.indexOf('tv4-') === 0; }) - .forEach(function(k) { ngModel.$setValidity(k, true); }); - - if (result.valid === false && - result.error && - (result.error.dataPath === '' || - result.error.dataPath === '/' + form.key[form.key.length - 1])) { - - // Set viewValue to trigger $dirty on field. If someone knows a - // a better way to do it please tell. - ngModel.$setViewValue(scope.modelArray); - error = result.error; - ngModel.$setValidity('tv4-' + result.error.code, false); - } - }; - - scope.$on('schemaFormValidate', scope.validateSchemaSelector); - - scope.hasSuccess = function() { - return ngModel.$valid && !ngModel.$pristine; - }; - - scope.hasError = function() { - return ngModel.$invalid; - }; - - scope.schemaError = function() { - return error; - }; - - } - - once(); - }); - } - }; - } -]); From e9528030dc3dd16b9aca0330fa75a637578d3563 Mon Sep 17 00:00:00 2001 From: Chase Sterling Date: Thu, 13 Aug 2015 00:53:59 -0400 Subject: [PATCH 5/7] Actuall make form selection work --- .../decorators/bootstrap/formselect.html | 10 +++++----- src/directives/formselect.js | 17 ++++++++++++++++ src/services/schema-form.js | 20 +++---------------- 3 files changed, 25 insertions(+), 22 deletions(-) create mode 100644 src/directives/formselect.js diff --git a/src/directives/decorators/bootstrap/formselect.html b/src/directives/decorators/bootstrap/formselect.html index 6b9fdcf5f..3dd3a30db 100644 --- a/src/directives/decorators/bootstrap/formselect.html +++ b/src/directives/decorators/bootstrap/formselect.html @@ -1,10 +1,10 @@ -
+
{{ form.title }}
- - -
+ + diff --git a/src/directives/formselect.js b/src/directives/formselect.js new file mode 100644 index 000000000..6eb3aeb06 --- /dev/null +++ b/src/directives/formselect.js @@ -0,0 +1,17 @@ +/** + * Directive that handles the model arrays + */ +angular.module('schemaForm').directive('sfFormSelect', ['sfSelect', 'schemaForm', 'sfValidator', 'sfPath', + function(sfSelect, schemaForm, sfValidator, sfPath) { + + return { + restrict: 'A', + scope: true, + require: '?ngModel', + link: function(scope, element, attrs, ngModel) { + scope.selectedForm = 0; + // TODO: Watch the model value and pick a form to match it + } + }; + } +]); diff --git a/src/services/schema-form.js b/src/services/schema-form.js index 08dd43328..7d4c976e7 100644 --- a/src/services/schema-form.js +++ b/src/services/schema-form.js @@ -314,8 +314,9 @@ angular.module('schemaForm').provider('schemaForm', } f.items = []; angular.forEach(schemas, function(s) { - // TODO: Set condition for each of these forms based on selection - f.items.push(defaultFormDefinition(name, s, options)); + var subForm = defaultFormDefinition(name, s, options); + subForm.notitle = true; + f.items.push(subForm); }); return f; @@ -562,21 +563,6 @@ angular.module('schemaForm').provider('schemaForm', traverse(schema, fn, path || []); }; - service.expandSchema = function(schema) { - - service.traverseSchema(schema, function(schema) { - // allOf schemas should be merged into the parent - if(schema.allOf) { - for(i=0; i Date: Thu, 13 Aug 2015 18:12:41 -0400 Subject: [PATCH 6/7] Add allOf support --- src/services/schema-form.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/services/schema-form.js b/src/services/schema-form.js index 7d4c976e7..c361db9ed 100644 --- a/src/services/schema-form.js +++ b/src/services/schema-form.js @@ -296,9 +296,9 @@ angular.module('schemaForm').provider('schemaForm', var formselect = function(name, schema, options) { var types = stripNullType(schema.type); if (!(schema.oneOf || schema.anyOf || angular.isArray(types))) return; - schemas = []; var f = stdFormObj(name, schema, options); f.type = 'formselect'; + var schemas = []; // TODO: What if there are more than one of these keys in the same schema? if (angular.isArray(types)) { angular.forEach(types, function(type) { @@ -322,10 +322,22 @@ angular.module('schemaForm').provider('schemaForm', return f; }; + var allof = function(name, schema, options) { + if (schema.allOf) { + var extended = schema; + var allOf = schema.allOf; + delete schema.allOf; + angular.forEach(allOf, function(s) { + extended = extendSchemas(s, extended); + }); + return defaultFormDefinition(name, extended, options); + } + }; + //First sorted by schema type then a list. //Order has importance. First handler returning an form snippet will be used. var defaults = { - any: [formselect], + any: [allof, formselect], string: [select, text], object: [fieldset], number: [number], From 16a48b3009a07e7578a46377a962c06a0062adf6 Mon Sep 17 00:00:00 2001 From: Chase Sterling Date: Fri, 14 Aug 2015 02:48:35 -0400 Subject: [PATCH 7/7] Auto select form based on model Change model when form is changed --- .../decorators/bootstrap/formselect.html | 2 +- src/directives/formselect.js | 35 +++++++++++++++++++ src/services/schema-form.js | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/directives/decorators/bootstrap/formselect.html b/src/directives/decorators/bootstrap/formselect.html index 3dd3a30db..8719d8929 100644 --- a/src/directives/decorators/bootstrap/formselect.html +++ b/src/directives/decorators/bootstrap/formselect.html @@ -1,4 +1,4 @@ -
+
{{ form.title }}