validate.js icon indicating copy to clipboard operation
validate.js copied to clipboard

Being able to override attributeName

Open Strato opened this issue 8 years ago • 10 comments

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.

Strato avatar Aug 03 '16 15:08 Strato

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.

Strato avatar Aug 03 '16 16:08 Strato

I'll consider adding an attribute key mapper.

ansman avatar Aug 09 '16 16:08 ansman

+1 I am also in need of this.

fragosti avatar Aug 17 '16 02:08 fragosti

This looks like a duplicate of https://github.com/ansman/validate.js/issues/69

HillTravis avatar Sep 09 '16 20:09 HillTravis

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 [];
};

faboulaws avatar Nov 24 '16 10:11 faboulaws

Can someone please add this feature?

iSarCasm avatar Oct 04 '18 06:10 iSarCasm

any update on this? :)

Kepro avatar Jan 08 '19 11:01 Kepro

Can we make outputting the key in the error optional so we can define a totally custom error message?

sami616 avatar May 31 '19 10:05 sami616

Related to https://github.com/ansman/validate.js/issues/69

timmyomahony avatar Dec 18 '19 20:12 timmyomahony

@ansman what is the status?

mindaugasnakrosis avatar Aug 18 '20 13:08 mindaugasnakrosis