diff --git a/projects/schema-form/src/lib/model/formproperty.ts b/projects/schema-form/src/lib/model/formproperty.ts index e4e8ee43..5e911d7a 100644 --- a/projects/schema-form/src/lib/model/formproperty.ts +++ b/projects/schema-form/src/lib/model/formproperty.ts @@ -163,6 +163,22 @@ export abstract class FormProperty { */ public _runValidation(): any { let errors = this.schemaValidator(this._value) || []; + + // remove missing required property error if property is not visible + for (let i = errors.length - 1; i >= 0; i -= 1) { + const error = errors[i]; + if (error.code === "OBJECT_MISSING_REQUIRED_PROPERTY") { + let path = `${error.path.substring(1)}`; + if (path.substring(1) !== error.params[0]) { + path += `/${error.params.join("/")}`; + } + const requiredProperty = this.searchProperty(path); + if (requiredProperty && requiredProperty.visible === false) { + errors.splice(i, 1); + } + } + } + let customValidator = this.validatorRegistry.get(this.path); if (customValidator) { let customErrors = customValidator(this.value, this, this.findRoot()); diff --git a/src/app/json-schema-example/json-schema-example.component.ts b/src/app/json-schema-example/json-schema-example.component.ts index 551754b0..9a57fadd 100644 --- a/src/app/json-schema-example/json-schema-example.component.ts +++ b/src/app/json-schema-example/json-schema-example.component.ts @@ -17,6 +17,7 @@ import visibility_binding_example2 from './visibility-binding-example-schema2.js import visibility_binding_example3 from './visibility-binding-example-schema3.json'; import visibility_binding_example4 from './visibility-binding-example-schema4.json'; import sample_canonical_path from './sample-canonical-path.json'; +import required_only_if_visible from './required-only-if-visible.json'; import {AppService, AppData} from '../app.service'; import {ISchema} from 'ngx-schema-form'; @@ -46,6 +47,7 @@ export class JsonSchemaExampleComponent implements OnInit, OnDestroy { {label: 'Sample 6 - Visibility binding 3', event: this.changeSchemaVisibilityBinding3, selected: false}, {label: 'Sample 7 - Visibility binding 4', event: this.changeSchemaVisibilityBinding4, selected: false}, {label: 'Sample 8 - Canonical path', event: this.changeSchemaCanonicalPath, selected: false}, + {label: 'Sample 9 - Required only if visible', event: this.changeSchemaRequiredOnlyIfVisible, selected: false}, ]; constructor( @@ -247,6 +249,14 @@ export class JsonSchemaExampleComponent implements OnInit, OnDestroy { this.actions = {}; } + changeSchemaRequiredOnlyIfVisible() { + this.schema = required_only_if_visible as unknown as ISchema; + this.model = {}; + this.fieldBindings = {}; + this.fieldValidators = {}; + this.actions = {}; + } + disableAll() { Object.keys(this.schema.properties).map(prop => { this.schema.properties[prop].readOnly = true; diff --git a/src/app/json-schema-example/required-only-if-visible.json b/src/app/json-schema-example/required-only-if-visible.json new file mode 100644 index 00000000..02b9b9fa --- /dev/null +++ b/src/app/json-schema-example/required-only-if-visible.json @@ -0,0 +1,157 @@ +{ + "properties": { + "checkbox": { + "type": "boolean", + "title": "Checkbox", + "widget": "checkbox" + }, + "select": { + "type": "string", + "title": "Select", + "widget": "select", + "oneOf": [ + { + "description": "Option #1", + "enum": ["Option #1"] + }, + { + "description": "Option #2", + "enum": ["Option #2"] + }, + { + "description": "Option #3", + "enum": ["Option #3"] + } + ], + "visibleIf": { + "checkbox": [true] + } + }, + "multi-select": { + "type": "array", + "title": "Multi Select", + "widget": "select", + "minItems": 2, + "items": { + "type": "string", + "oneOf": [ + { + "description": "Option #1", + "enum": ["Option #1"] + }, + { + "description": "Option #2", + "enum": ["Option #2"] + }, + { + "description": "Option #3", + "enum": ["Option #3"] + } + ] + }, + "visibleIf": { + "checkbox": [true] + } + }, + "string": { + "type": "string", + "title": "String - Visible if Checkbox is checked", + "visibleIf": { + "checkbox": [true] + } + }, + "number": { + "type": "number", + "title": "Number - Visible if String is 'a'", + "widget": "number", + "visibleIf": { + "string": ["a"] + } + }, + "array": { + "type": "array", + "title": "Array", + "minItems": 2, + "items": { + "type": "object", + "properties": { + "array-checkbox": { + "type": "boolean", + "title": "Checkbox", + "widget": "checkbox" + }, + "array-select": { + "type": "string", + "title": "Select", + "widget": "select", + "oneOf": [ + { + "description": "Option #1", + "enum": ["Option #1"] + }, + { + "description": "Option #2", + "enum": ["Option #2"] + }, + { + "description": "Option #3", + "enum": ["Option #3"] + } + ], + "visibleIf": { + "array-checkbox": [true] + } + }, + "array-multi-select": { + "type": "array", + "title": "Multi Select", + "widget": "select", + "minItems": 2, + "items": { + "type": "string", + "oneOf": [ + { + "description": "Option #1", + "enum": ["Option #1"] + }, + { + "description": "Option #2", + "enum": ["Option #2"] + }, + { + "description": "Option #3", + "enum": ["Option #3"] + } + ] + }, + "visibleIf": { + "array-checkbox": [true] + } + }, + "array-string": { + "type": "string", + "title": "String - Visible if Checkbox is checked", + "visibleIf": { + "array-checkbox": [true] + } + }, + "array-number": { + "type": "number", + "title": "Number - Visible if String is 'a'", + "widget": "number", + "visibleIf": { + "array-string": ["a"] + } + } + }, + "required": [ + "array-select", + "array-multi-select", + "array-string", + "array-number" + ] + } + } + }, + "required": ["select", "multi-select", "string", "number", "array"] +}