validate.js
validate.js copied to clipboard
Being able to override attributeName
Hello,
I have the following problem: I would like to be able to override the attribute name in the error messages.
For example, I have a countryCurrency field in my form, that's a business term, but my application is in french, and the label displayed over the field is 'Devise du pays'.
Using validate.js, I get the error message 'CountryCurrency is invalid' (actually we translated the 'is invalid' part), which is at best not very pretty, but also can be confusing for our users.
I would like to be able to do this:
validate({ countryCurrency: '€' }, {
countryCurrency: {
attributeName: 'Devise du pays',
presence: true
}
})
So I can have a nice error message 'Devise du pays is invalid'.
I realize the attribute name is not a constraint and has not much to do with it, but that's the most logical place I could find. Maybe you could rename the parameter 'contraints' to 'rules', which would make more sense if attributeName is added to it.
Writing this, I'm thinking that I could possibly do this:
// I haven't tested this code
validate({ 'Devise du pays': '€' }, {
'Devise du pays': {
presence: true
}
})
But you see, I'm leveraging validate.js by linking it to redux-form. I suppose you're not familiar with it, but it happens that the errors object returned by default by validate.js (grouped) fits perfectly what redux-form is expecting. I'm doing this:
var constraints = 'REDACTED';
var validator = function (values) {
// values is passed by redux-form and is a plain object of { field-name: value }
// just what validate.js needs
return validate(values, constraints);
};
...and give validator to redux-form. That works very well, except for this attribute name problem.
I can see I'm not the only one having this problem: #69 #102
But proposed solutions so far does not seem very nice to me.
I could do a PR of this if you're interested. I'm also considering to write a TypeScript definition for validate.js, since it's missing and would be useful.
For those interested, I ended up writing my own field/label translate function based on my idea in the previous post.
Here is the adapter. It's TypeScript code. I'm leaving it as is, with the french documentation.
import * as validate from 'validate.js';
import * as _ from 'lodash';
/**
* Permet de remplacer les clefs d'un objet JSON par d'autres clefs provenant d'un
* dictionnaire de correspondance, sans toucher aux valeurs.
* @param object Objet dont les clefs doivent être traduites.
* @param matching Dictionnaire de correspondance clef/valeur.
*/
const translate = (object, matching) => {
return _.mapKeys(object, (value, key) => matching[key]);
};
/**
* Permet de brancher ReduxForm et validate.js, tout en conservant les labels des champs.
* @param constraints Contraintes validate.js à appliquer aux champs.
* @param fieldLabelMatching Dictionnaire de correspondance entre les noms des champs
* et les labels à afficher dans les messages d'erreur.
*/
export const createReduxFormValidator = (
constraints,
fieldLabelMatching
) => {
// Those two properties are pre-calculated for performance reasons
const labelFieldMatching = _.invert<any>(fieldLabelMatching);
const constraintsTranslated = translate(constraints, fieldLabelMatching);
return (values) => {
const valuesTranslated = translate(values, fieldLabelMatching);
const errors = validate(valuesTranslated, constraintsTranslated);
const errorsTranslatedBack = translate(errors, labelFieldMatching);
return errorsTranslatedBack;
};
};
And here is an example of how to use it:
var fieldLabelMatching = {
'countryCurrency': 'Devise du pays'
};
var constraints = {
'countryCurrency': {
presence: true
}
};
var validator = createReduxFormValidator(constraints, fieldLabelMatching);
Though, I still believe validate.js could use a parameter to override the attribute name. That would have allowed me not to have to write this tedious code, and give a little performance boost since all those back and forth translations wouldn't be necessary.
I'll consider adding an attribute key mapper.
+1 I am also in need of this.
This looks like a duplicate of https://github.com/ansman/validate.js/issues/69
I was able to work around this with by
- use a wrapper function for validate.js
- create a custom validator named attrLabel that always return an empty error list
- call validate with option fullMessage = false. (This give messages without attribute name)
- when errors are received i add the attribute as prefix
- the field constraint has a validator named attrLabel i use this attribute as the field label.
- otherwise I proceed as usual
Hope this helps someone
validationHelper.validateModel = function validateModel(modelData, constraints, resourceType) {
const validationErrors = validate(modelData, constraints, {fullMessages: false});
const errors = [];
if (validationErrors) {
for (const field in validationErrors) {
if (validationErrors.hasOwnProperty(field)) {
validationErrors[field].forEach((errorMsg) => {
const fieldLabel = constraints[field].attrLabel ?constraints[field].attrLabel:validate.capitalize(validate.prettify(field));
const fullMessage = fieldLabel + " " errorMsg;
errors.push(new ErrorModel(field, resourceType, constantsHelper.errorCodes.validation, fullMessage));
});
}
}
}
return errors;
};
validate.validators.attrLabel = function attrLabel() {
return [];
};
Can someone please add this feature?
any update on this? :)
Can we make outputting the key in the error optional so we can define a totally custom error message?
Related to https://github.com/ansman/validate.js/issues/69
@ansman what is the status?