Skip to content

custom error messages not showing? #369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
plong0 opened this issue Apr 27, 2015 · 9 comments
Closed

custom error messages not showing? #369

plong0 opened this issue Apr 27, 2015 · 9 comments

Comments

@plong0
Copy link

plong0 commented Apr 27, 2015

I've got a custom form directive with an async validator. The validation is working and setting the field valid/invalid depending on if the validation promise resolves or rejects.

Trouble I am having is with getting the error message to come through. I am using the code:
scope.$broadcast('schemaForm.error.'+ngModel.$name, 'unique', 'That thing is not unique!');

and to clear the error message:
scope.$broadcast('schemaForm.error.'+ngModel.$name, 'unique', true);

is this not the proper way to set the custom error message? I tried setting it in my formDefaults validationMessage, "unique": "That thing is not unique" and that works, but I would prefer to have the message coming from my validator.

unique is the name of the $asyncValidators entry, which doesn't seem to make a difference.

@plong0
Copy link
Author

plong0 commented Apr 27, 2015

Ok, now this is interesting... I just got it working by using scope.$parent.$broadcast in one case, and scope.$parent.$parent.$broadcast in a different case.

With a form looking like:

"form": [
    { "key": "username", "type": "new-username", "placeholder": "Username or Email address", "required": true },
    { "key": "password", "type": "password", "title": "Password" },
    { "key": "password_confirm", "type": "password-confirm", "title": "Confirm Password", "condition": "model.password" },
    { "type": "section", "htmlClass": "btn-group inline-btn-group", "items": [
        { "type": "submit", "style": "btn-primary", "title": "Register" },
        { "type": "button", "style": "btn-default", "title": "Cancel", "onClick": "cancel()" }
    ]}
]

password-confirm uses $validators and needs 2x $parent.
new-username uses $asyncValidators and needs 1x $parent.

I would guess that the event listener is on the form scope? how can we broadcast to it from the custom validation?

@plong0
Copy link
Author

plong0 commented Apr 27, 2015

I think I would like it if I could do something like:

  1. ngModel.$error.unique = "That is not unique!";
    or
  2. ngModel.$error.uniqueUsername = "Username is not unique!";

Seems to always set $error.<validatorName> = true; when it rejects rather than using the message I have set. Tried rejecting("Not unique!").

For now, I am using option 2 and in my formDefaults: { validationMessage: { "uniqueUsername": "Username is not unique" } } ...

@davidlgj
Copy link
Contributor

Hi @plong0,

broadcasting the error message is for setting an error on a field from outside of schema form, not from inside.

The way it works currently is that the name you give your asyncValidator gets used as it's error key, sf-message checks for it in the fields validationMessage, then the forms options and then the global error messages. So for your error message to appear you need to add it to the form definition or with sf-options

Edit: Changed sf-error to sf-messages which of course is the real name of the directive

@davidlgj
Copy link
Contributor

Just a note, the problem your having with the events is just that it's meant to be a $broadcast on the form, not from inside. Its's the top directive for that field you need to hit with your event.

@plong0
Copy link
Author

plong0 commented Apr 29, 2015

Hey, thanks for the clarity @davidlgj . I was suspecting that was the case...
The trouble is that my async validator has a couple different error messages it could set (ie. "Username taken" or "Email taken") is there currently a way to do that?

@davidlgj
Copy link
Contributor

@plong0 I don't think its possible, I guess they designed asyncValidators to just do one validation :)

From outside of schema form you can use the schemaForm.error.* events but from inside an add-on you will need to do something different.

But you could probably hack something togheter by using a common service to do the actual call to the server, if they share the same promise then only one call is needed.

@plong0
Copy link
Author

plong0 commented May 4, 2015

Hmm, interesting... I thought setting a value in ngModel.$errors would do the trick... oh well. I thought of a way to refactor so it's no longer a problem.
Thanks for the reply @davidlgj

@plong0
Copy link
Author

plong0 commented May 7, 2015

back with good news!
as I was re-reading the docs about validation messages, I came across that shiny little gem, "sfErrorMessageProvider" ... configuring the 'uniqueEmail' and 'uniqueUsername' messages in there, and then in the asyncValidator, ngModel.$setValidity('uniqueEmail', false) or ngModel.$setValidity('uniqueUsername, false) does exactly what I want :D

An interesting thing I learned is that if you set multiple validationErrorKeys to false, it uses whichever one is set first.

I also did a further test for if I ever want to set an error message on-the-fly (like from the server or otherwise dynamically generated by the validator)... then it is possible in a way like:

// in the module config, set the error message as a function
sfErrorMessageProvider.setDefaultMessage('uniqueUsername', function(ctx){ return (ctx.form.uniqueUsername?ctx.form.uniqueUsername:"silly goose!"); });
// in the validator, generate the error message into the scope.form
ngModel.$setValidity('uniqueUsername', false);
scope.form.uniqueUsername = 'This error is dynamic ("'+value+'" is '+value.length+' characters long)!';

(I think if I ever did need that, I would encapsulate the dynamic error messages into a form.messages object or something like that)

So that's pretty cool. I think that answered all my questions about how to generate and set error messages.

@plong0
Copy link
Author

plong0 commented Jul 22, 2015

I will add that if you are using ngModel.$setValidity('someCustomError', false); then you should also add a $parser that resets it. (do this for every custom error your $validator/$asyncValidator might set, including the name of the validator itself.)
ex:

// a custom $asyncValidator that takes a second to check if modelValue == 'test'
ngModel.$asyncValidators.isTest = function(modelValue, viewValue){
    var defer = $q.defer();
    $timeout(function(){
        if(modelValue == 'test'){
            ngModel.$setValidity('notTest', true);
            defer.resolve();
        }
        else{
            ngModel.$setValidity('notTest', false);
            defer.reject();
        }
    }, 1000);
    return defer.promise;
}

// a parser that resets the custom validation flags
ngModel.$parsers.push(function(viewValue){
    ngModel.$setValidity('notTest', true); // the custom error message
    ngModel.$setValidity('isTest', true); // the name of the $asyncValidator
    return viewValue;
});

(I think this is a similar approach of how a-s-f is managing the custom tv4 errors)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants