angular-schema-form icon indicating copy to clipboard operation
angular-schema-form copied to clipboard

Not required nested object form fields validation

Open hlobit opened this issue 7 years ago • 3 comments

Enhancement

As a user, when I don't fill in any of the fields of a nested object I should be able to validate if schema does not specify this object as required.

Expected behaviour

I expected the model to be valid if it successfully validates with json schema. For instance, tv4 validates the following model with schema :

{
  "name": "John Smith",
  "email": "[email protected]"
}
{
  "type": "object",
  "title": "Newsletter subscription",
  "properties": {
    "name": {
      "title": "Name",
      "type": "string"
    },
    "email": {
      "title": "Email",
      "type": "string"
    },
    "comment": {
      "title": "Your comment (not required)",
      "type": "object",
          "properties": {
            "rate": {
              "title": "Rate",
              "type": "integer"
            },
            "review": {
              "title": "Review",
              "type": "string"
            }
          },
          "required": [
            "rate",
            "review"
          ]
    }
  },
  "required": [
    "name",
    "email"
  ]
}

Actual behaviour

Angular Schema Form considers the form invalid and highlights red the nested object form fields.

Demo

Click OK and see those errored fields

Related issues

I didn't find any issue related.

@json-schema-form/angular-schema-form-lead

hlobit avatar Mar 14 '17 14:03 hlobit

@hlobit that isn't likely in the near future as tv4 is run at the field level not on the entire object. Ideally we will find a way to upgrade away from tv4 to a validator fast enough to make whole object validation an option, but there's a lot of work in that obviously.

To replicate the outcome you desire in the short term, you would have to define the form with a field (checkbox maybe) to trigger a condition on a fieldset with the child object.

Anthropic avatar Mar 15 '17 22:03 Anthropic

@Anthropic nice workaround for the moment, will do that with a checkbox, this is also more explicit for the user.

I couldn't find issues related to this, maybe there are other side effects due to the fact that validation is performed at field level, but apparently not reported yet...

hlobit avatar Mar 17 '17 12:03 hlobit

It would be quite easy to add a directive to your app to watch for a style you put in your ui-schema which then does an additional validation from an object level. I did it for a very basic support of anyOf but you could certainly modify it to validate from any point within the form all the child validation.

The allowInvalid stops the child validations, so up to you if that is needed. It then runs the tv4 validation directly itself.

(function(angular, undefined) {'use strict';

  angular
    .module('schemaForm')
    .directive('oyInline', [ 'schemaForm', 'sfValidator', 'sfPath', 'sfSelect',
      function(schemaForm, sfValidator, sfPath, sfSelect) {
        return {
          restrict: 'A',
          require: 'ngModel',
          link: function(scope, element, attrs, ngModel) {
            var useKey = sfPath.stringify(scope.form.key),
                schema = {},
                title = scope.form.title || scope.form.key.join('.') || '';

            scope.invalidAnyOf = false;

            angular.copy(scope.form.schema, schema);

            if (schema.properties && schema.anyOf) {
              scope.form.schema.allowInvalid = true;
              delete schema.properties;
              delete schema.description;
            };

            ngModel.$name = title;
            ngModel.$options = {allowInvalid: true}

            scope.$watchCollection('model' + useKey, function(newVal, oldVal) {
              if (ngModel.$validate) {
                ngModel.$validate();
                if (ngModel.$invalid) { // The field must be made dirty so the error message is displayed
                  ngModel.$setValidity('anyOf', false);
                  scope.invalidAnyOf = true;
                }
                else {
                  ngModel.$setValidity('anyOf', true);
                  scope.invalidAnyOf = false;
                }
              }
              else {
                ngModel.$setViewValue(ngModel.$viewValue);
              }
            });

            ngModel.$validators = {
              anyOf: function(modelValue, viewValue) {
                tv4.validate(modelValue, schema);
                return tv4.valid;
              }
            };

            // Listen to an event so we can validate the input on request
            scope.$on('schemaFormValidate', function() {
              if (ngModel.$validate) {
                ngModel.$validate();
                if (ngModel.$invalid) { // The field must be made dirty so the error message is displayed
                  ngModel.$dirty = true;
                  ngModel.$pristine = false;
                }
              }
              else {
                ngModel.$setViewValue(ngModel.$viewValue);
              };
            });
          }
        };
      }
    ]);
})(window.angular);

Anthropic avatar Mar 20 '17 03:03 Anthropic