json-schema-form / angular-schema-form

Generate forms from a JSON schema, with AngularJS!
https://json-schema-form.github.io/angular-schema-form
MIT License
2.47k stars 653 forks source link

Custom Validator, disable onRender validation #876

Open radvansky-tomas opened 7 years ago

radvansky-tomas commented 7 years ago

Hi, could somebody advice me what I am doing wrong. I am trying to implement custom validators. With simple example of:

$validators: {
          noBob: function(value) {
            console.log(value);
            return false;
          }
   }

Every time I open page, my field is being validated => validation message is shown. But My expected behaviour is perform validation when I want -> so for example after submit, or onblur etc...I tried all suggested options from documentation, but this validator is ALWAYS called on render.

I tried even my own decorator and use hasError() on ng-if/show but again it did not work!

So could you advise how to implement custom validator which leaves you full control of triggering event?!

Anthropic commented 7 years ago

I'm wondering if you could set a scope attribute on first run and don't run until it is set? I'm not sure it would work as angular forms can re-trigger validation more than once, but it may work. If you can find something in the code which could avoid it, I'm happy to take a look at making it part of the validateOnRender option behaviour.

radvansky-tomas commented 7 years ago

So do you suggest to update sfValidate directive, set some flag there?

Sent from my iPhone

On 5 May 2017, at 00:31, Marcel J Bennett notifications@github.com wrote:

I'm wondering if you could set a scope attribute on first run and don't run until it is set? I'm not sure it would work as angular forms can re-trigger validation more than once, but it may work. If you can find something in the code which could avoid it, I'm happy to take a look at making it part of the validateOnRender option behaviour.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

Anthropic commented 7 years ago

No I was wondering, not certain, but wondering if you could set this.hasRun = 1 at the end and test for it at the beginning. Haven't tried it, just a thought.

radvansky-tomas commented 7 years ago

I tried to delay setting validators completely and call scope.apply after...but It always perform that validation immediately after assignment and show error in schemaform

Anthropic commented 7 years ago

Can you test for pristine? Not run the validation if the form hasn't been altered?

radvansky-tomas commented 7 years ago

You mean inside validators itself ?! Based on docs validator takes only one argument (value) which is object from ng-model. How do you suggest to get reference of that particular form. Even if this does not sound as best practice I would try it...but I have to idea how to obtain form reference within validator...(imagine that you have multiple forms per page)

Anthropic commented 7 years ago

What's on the 'this' object? Anything that may help? Sorry I can't test a solution I don't have a plunker handy and I'm at work :)

radvansky-tomas commented 7 years ago

Obviously you have schema, form layout and model. You are defining validators inside form layout. And this custom validators are having this format:

$validators: { noBob: function(value) { if (angular.isString(value) && value.indexOf('Bob') !== -1) { return false; } return true } }

In this case "value" is object/primitive type from ng-model defined within model in form definition: <form sf-schema="schema" sf-form="form" sf-model="model"></form>

So my question is how do you inject that particular form reference into $validators?

radvansky-tomas commented 7 years ago

Example is here: https://embed.plnkr.co/WwBHmh/

Try to 'hide' $validator on render, by not using 'hacks'. IE I want to perform validator once form is touched / submit button is pressed. As it is for "email" field -> by using internal validator (email pattern)

Anthropic commented 7 years ago

It would be easier with the alpha as each element would have a class to access, I don't think the old version will work without applying a style to the outer element and looking it up that way.

radvansky-tomas commented 7 years ago

I have no idea what are you talking about 🤣 There is no alpha channel involved and even if it was it would be hack as hell...

Anthropic commented 7 years ago

@radvansky-tomas the current dev branch of this library is the alpha of v1.0.0 it has a substantial amount of fixes and changes in it and should be much more stable, despite being labelled an alpha, than the current release. Both still have plenty of things I want to fix, but it would be worth looking into as it would possibly make your goal much easier to achieve as it adds appropriate classes and tags to look up the values. I still may be able to change the behaviour, all I'm doing in comments here is trying to help you with an interim solution.

radvansky-tomas commented 7 years ago

I've updated plunker to latest source from dev branch - https://embed.plnkr.co/WwBHmh/ I cant see any difference in end result. Validation is still triggered on load.

Anthropic commented 7 years ago

This will work for your example case:

      $validators: {
        noBob: function(value) {
          if(angular.element($('[name=comment]')).scope().ngModel.$pristine) return true;
          return false;
        }
      }

You can also modify $('[name=comment]') to point to your root scope instead if you want to have it access a function there to determine validity.

radvansky-tomas commented 7 years ago

Yes, but unfortunately, you've hardcoded element name and diminished whole point of dynamic forms. Plus looking for element via jquery...

Thing is that these "custom" validators dont have reference neither to form / element ... And in my case I am adding elements in dynamic way to the layout...so I cannot really "hardcode" strings

Anthropic commented 7 years ago

That is completely covered by the last sentence isn't it? If you point to your root form, you can do whatever you like with whatever scope you like, it's as flexible as you want to make it.

Take a look at #847 I'm waiting for feedback on a solution which I think would help you, maybe you can provide some feedback on the potential solution.