Skip to content
This repository was archived by the owner on Dec 12, 2021. It is now read-only.

Being able to override attributeName #148

Open
Strato opened this issue Aug 3, 2016 · 10 comments
Open

Being able to override attributeName #148

Strato opened this issue Aug 3, 2016 · 10 comments
Milestone

Comments

@Strato
Copy link

Strato commented Aug 3, 2016

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
Copy link
Author

Strato commented Aug 3, 2016

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.

@ansman
Copy link
Owner

ansman commented Aug 9, 2016

I'll consider adding an attribute key mapper.

@ansman ansman added this to the Next milestone Aug 9, 2016
@fragosti
Copy link

+1 I am also in need of this.

@HillTravis
Copy link

This looks like a duplicate of #69

@ansman ansman modified the milestones: 0.11.0, Next Nov 5, 2016
@faboulaws
Copy link

faboulaws commented Nov 24, 2016

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

@ansman ansman modified the milestones: 0.12.0, Next Oct 17, 2017
@iSarCasm
Copy link

iSarCasm commented Oct 4, 2018

Can someone please add this feature?

@Kepro
Copy link

Kepro commented Jan 8, 2019

any update on this? :)

@sami616
Copy link

sami616 commented May 31, 2019

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

@timmyomahony
Copy link

Related to #69

@mindaugasnakrosis
Copy link

@ansman what is the status?

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

No branches or pull requests

10 participants