validation icon indicating copy to clipboard operation
validation copied to clipboard

Dynamic validation error messages

Open fracz opened this issue 7 years ago • 6 comments

I'm submitting a feature request

Currently, it is impossible to create a dynamic validation error message. For example, I want to validate IBAN account number. I configure the rule as follows:

ValidationRules
    .ensure('account').displayName("Account number")
    .satisfies(account => getActualChecksum(account) == calculateChecksum(account))
    .withMessage("Given IBAN number is invalid");

The validation message could be much more informative, for example Given IBAN number has cheksum 34 but it should be 56.

What about allowing to pass a callback that will generate a validation message based on given value? This should solve all of the cases where the validation message should be built based on the given value or something else dynamic.

ValidationRules
    .ensure('account').displayName("Account number")
    .satisfies(account => getActualChecksum(account) == calculateChecksum(account))
    .withMessage(account => "Given IBAN has checksum " + getActualChecksum(account) + " but it should be " +calculateChecksum(account));

OR it should be possible to define special parameters for message in addition to existing $displayName and $value, e.g.

ValidationRules
    .ensure('account').displayName("Account number")
    .satisfies(account => getActualChecksum(account) == calculateChecksum(account))
    .withMessage("Given IBAN has checksum ${actualChecksum} but it should be ${correctChecksum}")
    .withMessageParamsBuilder(account => {actualChecksum: getActualChecksum(account), correctChecksum: calculateChecksum(account)});

What do you think?

fracz avatar Jan 04 '18 22:01 fracz

you could do this:

.withMessage("Given IBAN number has checksum ${calculateChecksum($value)} but it should be ${getActualChecksum($value)}");

jdanyow avatar Jan 05 '18 09:01 jdanyow

How should that work? Where should I define the getActualChecksum and calculateChecksum methods so they are corretly resolved? They are not global. In the above example they have been imported to the file I defined the rules in, e.g. import {getActualChecksum} from "./iban-checksum". Writing the message as you suggested results in empty replacements, no errors in console.

fracz avatar Jan 05 '18 10:01 fracz

Ok, you have pushed me into the right direction. You can pass the functions into the rule config, i.e.

ValidationRules
    .ensure('account').displayName("Account number")
    .satisfies(account => getActualChecksum(account) == calculateChecksum(account), {getActualChecksum, calculateChecksum})
    .withMessage("Given IBAN number has checksum ${$config.calculateChecksum($value)} but it should be ${$config.getActualChecksum($value)}");

and it works, indeed.

However, I think this is an abuse of what rule's config has been designed for.

And it does not solve the situation when an async function is used in satisfies and the backend responds with custom replacements. I mean: backend validation not only tells that the input is wrong but also what is wrong with it.

fracz avatar Jan 05 '18 10:01 fracz

Note that if the thing you're trying to compute dynamically is in the object the rules apply to you can use this:

.withMessage('Something or other: ${$object.thePropertyNeeded}')

ricardograca avatar Mar 01 '19 16:03 ricardograca

There should be something like $validationContext passed to any validation rule/function. Element, object, value, $config,... should be moved somehow under the $validationContext instance.

Then, $validationContext would be "the truest" place to get "a dynamic message" to be rendered, since it could be constructed by a validation function.

Now, the validation code works with arguments , instead of single argument in the form of $validationContext instance, extensible & configurable e.g. by a 'validation context factory'.

PetrMotlicek avatar Aug 12 '20 08:08 PetrMotlicek

FYI this requirement is addressed in Aurelia 2. In Aurelia 2 you can create your own custom rule class. This gives the encapsulation, as @PetrMotlicek suggests. Every rule has an execute method, which can be used to set any rule instance properties. In addition, the message template supports accessing the rule instance properties using $rule.property syntax. For more info, refer https://docs.aurelia.io/app-basics/validating-data.

Sayan751 avatar Aug 20 '20 17:08 Sayan751