Comments (34)
I'm not a fan of the service idea in the addon itself, it would require a lot of rework since most of the addon are vanilla JS modules with no knowledge of Ember. Instead, you can use computed properties on an Ember.Object
:
const Messages = Ember.Object.extend({
intl: Ember.inject.service(),
inclusion: computed('intl', function() {
// ...
})
});
export default Messages.create();
from ember-changeset-validations.
Here's what I ended up doing, in case anyone else ends up here looking for help: https://gist.github.com/jmacqueen/6d31aaa5ba5f5841d123d0406f1f86c5
from ember-changeset-validations.
Hi all,
I have just forked this repo in order to implement this feature. @jmacqueen gave a good example on how to connect the Ember IoC with the messages.
Following his advice, I created an instance initializer that would pass the Application instance to the get-messages.js
file in order to lookup them up via Ember container. Using the container there is no need to iterate through all defined modules and addons in order to find the custom validations/messages.js
file.
You can check the fork here
To use this feature, you would simply need to create an instance-initializer
in your application and define it like so:
export {default} from 'ember-changeset-validations/instance-initializers/ember-changeset-validations';
Then in your validations/messages.js
file, you can define a property or implement the messageForKey
function to load a message from either i18n
, intl
or any Ember Service:
import Ember from 'ember';
const { get, computed } = Ember;
export default Ember.Object.extend({
i18n: Ember.inject.service(),
i18nName: computed('i18n.locale', function () {
return this.t('validations.i18nName');
}),
messageForKey(key) {
const i18n = this.get('i18n');
key = `validations.${key}`;
if (i18n.exists(key)) {
return i18n.t(key).toString();
}
}
});
If you are ok with this approach, I would gladly make a PR to incorporate these changes.
While working on this, I realised that that a simple API could be exposed in order to load custom messages and field descriptions.
From the current issues it seems that there is a need for further customisation. It would be great if we could make this library be even more flexible with validation messages.
My suggestions would be to expose messageForKey
or descriptionForKey
functions. Message and description lookup would look like this:
Ember.Mixin.create({
// default messages
defaults: {},
getDescriptionFor(key = '') {
let value;
// Check if there is a custom lookup function defined
if (canInvoke(this, 'descriptionForKey')) {
value = this.descriptionForKey(key);
}
// Generate default description
if (isNone(value)) {
value = capitalize(dasherize(key).split(/[_-]/g).join(' '));
}
return value;
},
// use the unknown property hook in Ember.Object in order to find
// messages which were not defined directly on the object
unknownProperty(key = '') {
let value;
// Check if there is a custom lookup function defined
if (canInvoke(this, 'messageForKey')) {
value = this.messageForKey(key);
}
// Play nice with ObjectProxy instances
if (isNone(value)) {
value = this._super(key);
}
// Load default message
if (isNone(value)) {
value = get(this, `defaults.${key}`);
}
return value;
}
})
As this change would be a rather big one, I would be good to agree on this beforehand :)
from ember-changeset-validations.
@martndemus @poteto Could you suggest some solution for this issue, guys? I'm using ember-i18n service for my translations, and I've tried the option #94 (comment) , but this doesn't work anymore. Any other elegant suggestion? Thanks for your great work btw!
from ember-changeset-validations.
Thanks,
Using CPs inside the messages object works without problems.
(Except that i have to manually inject the intl
service using a container)
Another question:
Would it make sense to allow users to pass their own buildMessage
function to move string template interpolation away from the validation-errors
module to a pluggable part of the app (primarily i18n related libs)?
That way one isn't coupled to the string format ember-changeset-validations is using.
It could be solved by allowing the user to pass validatorOptions
to the lookupValidator
method: lookupValidator(Validator, {buildMessage: () => 'foo'})
which in turn will pass the validatorOptions into each validator.
Something like this: makepanic@8cca573
from ember-changeset-validations.
what you can do is to register a seperate lookup util.
app/utils/lookup-validator.js
import originalLookupValidator from 'ember-changeset-validations';
import { merge } from '@ember/polyfills';
import { isArray } from '@ember/array';
export default function lookupValidator(validationMap = {}, options = {}) {
return ({ key, newValue, oldValue, changes, content }) => {
let validationResult = originalLookupValidator(validationMap)({ key, newValue, oldValue, changes, content });
if (options.intl && options.intl.t && isArray(validationResult)) {
validationResult = validationResult.map((v) => {
if (v.message && v.attrs) {
return options.intl.t(v.message, merge(v.attrs, { key: options.intl.t(`validations.changeset.keys.${key}`) }));
}
return v;
})
}
return validationResult;
}
}
app/validations/messages.js
export default {
inclusion: 'validations.changeset.messages.inclusion',
exclusion: 'validations.changeset.messages.exclusion',
invalid: 'validations.changeset.messages.invalid',
confirmation: "validations.changeset.messages.confirmation",
accepted: 'validations.changeset.messages.accepted',
empty: "validations.changeset.messages.empty",
blank: 'validations.changeset.messages.blank',
present: "validations.changeset.messages.present",
collection: 'validations.changeset.messages.collection',
singular: "validations.changeset.messages.singular",
tooLong: 'validations.changeset.messages.tooLong',
tooShort: 'validations.changeset.messages.tooShort',
between: 'validations.changeset.messages.between',
before: 'validations.changeset.messages.before',
onOrBefore: 'validations.changeset.messages.onOrBefore',
after: 'validations.changeset.messages.after',
onOrAfter: 'validations.changeset.messages.onOrAfter',
wrongDateFormat: 'validations.changeset.messages.wrongDateFormat',
wrongLength: 'validations.changeset.messages.wrongLength',
notANumber: 'validations.changeset.messages.notANumber',
notAnInteger: 'validations.changeset.messages.notAnInteger',
greaterThan: 'validations.changeset.messages.greaterThan',
greaterThanOrEqualTo: 'validations.changeset.messages.greaterThanOrEqualTo',
equalTo: 'validations.changeset.messages.equalTo',
lessThan: 'validations.changeset.messages.lessThan',
lessThanOrEqualTo: 'validations.changeset.messages.lessThanOrEqualTo',
otherThan: 'validations.changeset.messages.otherThan',
odd: 'validations.changeset.messages.odd',
even: 'validations.changeset.messages.even',
positive: 'validations.changeset.messages.positive',
multipleOf: 'validations.changeset.messages.multipleOf',
date: 'validations.changeset.messages.date',
email: 'validations.changeset.messages.email',
phone: 'validations.changeset.messages.phone',
url: 'validations.changeset.messages.url',
formatMessage: (message, attrs) => {
return { message, attrs };
}
}
/translations/de-de.yml
##############################
# VALIDATIONS
##############################
validations:
changeset:
messages:
inclusion: '{key} is not included in the list'
exclusion: '{key} is reserved'
invalid: '{key} is invalid'
confirmation: "{key} doesn't match {on}"
accepted: '{key} must be accepted'
empty: "{key} can't be empty"
blank: '{key} must be blank'
present: "{key} can't be blank"
collection: '{key} must be a collection'
singular: "{key} can't be a collection"
tooLong: '{key} is too long (maximum is {max} characters)'
tooShort: '{key} is too kurz (minimum is {min} characters)'
between: '{key} must be between {min} and {max} characters'
before: '{key} must be before {before}'
onOrBefore: '{key} must be on or before {onOrBefore}'
after: '{key} must be after {after}'
onOrAfter: '{key} must be on or after {onOrAfter}'
wrongDateFormat: '{key} must be in the format of {format}'
wrongLength: '{key} is the wrong length (should be {is} characters)'
notANumber: '{key} must be a number'
notAnInteger: '{key} must be an integer'
greaterThan: '{key} must be greater than {gt}'
greaterThanOrEqualTo: '{key} must be greater than or equal to {gte}'
equalTo: '{key} must be equal to {is}'
lessThan: '{key} must be less than {lt}'
lessThanOrEqualTo: '{key} must be less than or equal to {lte}'
otherThan: '{key} must be other than {value}'
odd: '{key} must be odd'
even: '{key} must be even'
positive: '{key} must be positive'
multipleOf: '{key} must be a multiple of {multipleOf}'
date: '{key} must be a valid date'
email: '{key} ist keine valide email'
phone: '{key} must be a valid phone number'
url: '{key} must be a valid url'
keys:
email: E-Mail
password: Passwort
and finally use it....
...
import lookupValidator from '../../../utils/lookup-validator';
...
return new Changeset({}, lookupValidator(UserValidations, {intl: this.intl}), UserValidations);
this way no other changes are required and it works out of the box with ember-form-for for example....
little hacky yes but this works as it should with every validator and its also possible to change locales at runtime. Hope this helps
from ember-changeset-validations.
Hi,
I've come up with a PR that allows to postpone i18n/intl work outside of ember-changeset-validations by making it return (optionally) an object instead of a String. It works wonders for us: #185
from ember-changeset-validations.
I was wondering if this addon could check whether message.js
export a POJO or an Ember.Object
. If it is an Ember object, it could take care of the creation and owner injection:
import Ember from 'ember';
const { computed } = Ember;
export default Ember.Object.extend({
i18n: Ember.inject.service(),
i18nName: computed('i18n.locale', function () {
return this.t('validations.i18nName');
})
});
// I do not create or export the object
And the addons would be responsible to:
import Messages from 'validations/messages.js';
Messages.create(
Ember.getOwner(this).ownerInjection()
);
Does it sound like it would work? And is it something you'd be willing to implement? cc @poteto @martndemus
from ember-changeset-validations.
Does the solution #94 (comment) still work? It seems computed properties aren't merged by Ember.merge
in https://github.com/DockYard/ember-changeset-validations/blob/c638e81a537c5e9fb427227cc0e35852d01a6919/addon/utils/with-defaults.js#L13-L15
from ember-changeset-validations.
Yesterday, I finally ran into the need to use a service in my validations. In my particular case, I needed to fetch a dynamic array of strings from my API to validate inclusion against. After reading this thread, I almost tried to make this work in this addon.
However, I realized that I would essentially be rebuilding a bunch of the stuff in ember-changeset-cp-validations. I decided to just start using that addon instead. I think that model is a lot more robust and fits better with any scenario where you need to access dynamic data provided by an Ember service. It was a pretty simple transition and I will probably move my other validations over if the need arises. Definitely recommended!
from ember-changeset-validations.
I've tried different approaches and addon to display/translate validations messages at runtime and finally I found an easy way to do it. I've followed https://github.com/poteto/ember-changeset-validations#overriding-validation-messages but instead of returning a real message I return a valid translation key for ember-i18n
.
// app/validations/messages.js
export default {
inclusion: 'errors.validations.inclusion',
exclusion: 'errors.validations.invalid',
invalid: 'errors.validations.invalid',
// ...
}
And now I my view I can use this key to translate validation message at runtime using the t
helper.
Like this:
{{#if changeset.isInvalid}}
<p>There were errors in your form:</p>
<ul>
{{#each changeset.errors as |error|}}
<li>{{error.key}}: {{t error.validation}}</li>
{{/each}}
</ul>
{{/if}}
from ember-changeset-validations.
@xcambar I have setup it on https://github.com/gauravjain028/ember-intl-changeset-error-handling
Template File : https://github.com/gauravjain028/ember-intl-changeset-error-handling/blob/master/app/templates/application.hbs
When in load the app, it give me js error
The intl string context variable 'description' was not provided to the string '{description} can't be blank'
from ember-changeset-validations.
@makepanic Are you using ember-i18n or equivalent?
If so, I could write a patch that tries to lookup the messages from an i18n service at run-time, that should account for a locale change.
from ember-changeset-validations.
Yes i'm using ember-intl
.
A configurable service sounds like a great idea.
from ember-changeset-validations.
That would work.
from ember-changeset-validations.
@makepanic How did you get this to work? I can't seem to sort out the manual injection of the (I'm using ember-i18n
) service using container. Do you have a link to your implementation?
from ember-changeset-validations.
@jmacqueen i went with passing a buildMessage
option to the lookupValidator
method (see makepanic@8cca573).
Message building happens by calling the provided buildMessage
function which in turn calls ember-intl to translate the given incoming validation message key.
from ember-changeset-validations.
Hei @jmacqueen, i'm seeing this error in my console:
Uncaught TypeError: _siteUtilsApplication.default.instance.lookup is not a function
Any ideias why?
Thank you! <3
from ember-changeset-validations.
@karellm I would be open to this. Do you have time to open a PR?
from ember-changeset-validations.
@poteto I tried but I'm not very familiar with Ember internals and add-ons development. this
is actually undefined
inside the utils
. It looks like it should be passed by buildMessage
which makes the API a little weird.
Also I'm not sure how to go about testing this since the resolver looks for validations/messages
so I can't have 2 different files (one POJO, one Ember.Object).
I'm happy to do it but I would really appreciate some pointers. Thanks!
from ember-changeset-validations.
@poteto, @karellm
Any progress on this? I find myself stuck trying to get an Ember.Object to be recognized from messages.js. As long as it's a simple POJO - no issues, but when wrapped in an Ember.Object, the add-on reverts to its defaults rather than using the provided object from messages.js.
from ember-changeset-validations.
We implemented the changes @jmacqueen did, and the breakpoint on the initialize method in instance-initializers/application.js is hitting. However nothing is hitting for our validations/messages.js file. Is there something that needs to be added to our validators file to get our translated messages file loaded?
A sample of our validator file...
import {
validateLength,
validateFormat
} from 'ember-changeset-validations/validators';
import { validatePhone, validateExtension } from 'ember-engine-contacts/validators/phone';
import { regularExpressions } from 'ember-validators/format';
import validateTwitter from 'ember-engine-contacts/validators/twitter';
export default {
workEmail: [
validateLength({ max: 254, allowNone: true, allowBlank: true }),
validateFormat({ type: 'email', allowNone: true, allowBlank: true, regex: regularExpressions.email })
]
};
I also tried removing any code we had in both app/validations/messages and addon/validations/messages with
export default {
email: 'FOOBAR'
}
as the doc states to do, but still the default message showed.
I can add 'message' to the object parameters in the validateFormat method, which works...but not sure how to get our overridden messages file to work.
Any help would be greatly appreciated!
from ember-changeset-validations.
@makepanic @martndemus @karellm @nandorstanko I've released an Ember Addon to apply ember-i18n
translations to these messages in a beta version here https://github.com/mirai-audio/ember-i18n-changeset-validations. Could use a few hands to try it before I release a v1.0.0
Edit.
I release v1.0.0
from ember-changeset-validations.
@0xadada Correct me if I'm wrong, but your solution doesn't support changing locale without reloading the app. That's a huge feature, that is a MUST HAVE for me... That is why I use ember-i18n addon in the first place. I've switched to ember-changeset-cp-validations+ember-i18n-cp-validations combo, and it's working for me. Probably slower this way, but not an issue so far.
from ember-changeset-validations.
from ember-changeset-validations.
While working on a new project with intl + changeset-validations, I've found another workaround (hack) to get this working without touching too many things:
- changeset-validations is retrieveing messages from ember-validators/messages
- if one overwrites
Messages.formatMessage
, one can provide a custom translation solution:- configure
validations/messages
to be a simple identity map where each key is its value. This causes formatMessage to be called with the error code (i.e.inclusion
).
- configure
export default {
inclusion: 'inclusion',
exclusion: 'exclusion',
...
url: 'url'
}
- change
Message.formatMessage
to take the error code "message" and context and pass it into intl:
Messages.formatMessage = (message, context = {}) => {
let errorKey = message;
if (isNone(errorKey) || typeof errorKey !== 'string') {
return intl.t('validations.invalid');
}
return intl.t(`validations.${errorKey}`, context);
}
Now if changeset-validations tries to format the translated template, it passes the error code and get's the translation using whatever you configured.
In ember-intl context one can easily add these error key translations.
validations:
inclusion: 'Ist nicht in der Liste enthalten'
...
I've added overwriting formatMessage
into the intl service init
hook and it looks like it's working fine.
from ember-changeset-validations.
I can confirm that @xcambar's solution is very flexible and works great for my use case.
from ember-changeset-validations.
FYI, #185 has been merged.
See the PR and this setion of the docs for info.
Should this issue be closed now?
from ember-changeset-validations.
Looks good. Can we maybe add an example on how to use this with intl/i18n?
I'm ok with closing this
from ember-changeset-validations.
I'm using it with something of the form (wrapped in a helper):
{{t (concat "path.to.errors." error.type) errors.context}}
from ember-changeset-validations.
I have kind of tackled this and our migration from ember-i18n
to ember-intl
at the same time. The one gotcha I ran into was that the {{t }}
helper from ember-i18n
allowed passing a hash of i18n paramaters, where the one from ember-intl
requires passing each as it's own parameter, which isn't ideal when we don't know the parameters upfront.
from ember-changeset-validations.
@xcambar passing errors.context
with name attribute is not working on my end ? Can you help with that ?
from ember-changeset-validations.
I can try :)
In order to ease investigation, can you share a twiddle or a repo that reproduces the behaviour, please?
from ember-changeset-validations.
I was having issues in octane but I was able to get a good workaround with custom validators.
import Component from '@glimmer/component';
import Changeset from 'ember-changeset';
import lookupValidator from 'ember-changeset-validations';
import { inject as service } from '@ember/service';
export default class MyComponent extends Component {
@service intl;
validator({ errorKey }) {
let errorMsg = this.intl.t(`${errorKey}.error.msg`);
return function(_, value) {
let isInValid = ....; // custom validation logic
if (isInValid) {
return errorMsg;
}
return true;
}
}
validators = {
name: this.validator({ errorKey: 'name.field' }),
email: this.validator({ errorKey: 'email.field' })
};
changeset = new Changeset(
{
name: this.name,
email: this.email
},
lookupValidator(this.validators),
this.validators
);
}
from ember-changeset-validations.
Related Issues (20)
- async validator is called multiple times with the same value HOT 2
- Date validator does not respect 'rawOutput' option HOT 2
- async validators can complete out of order HOT 4
- Documentation for rawOutput
- (Octane) skipValidate=true in helper does not work HOT 2
- (Octane) Documentation update suggestion: passing the validation instance HOT 1
- ember inspector silently polluting `changes`? HOT 1
- Button attribute not updating using classic components syntax HOT 1
- Access Service from validator class
- Freezed value in Input HOT 5
- Update to ember-validates v4 is breaking change HOT 2
- allowBlank doesn't work with validateFormat() HOT 1
- [Proposal] Use isEmpty for the date validator's allowBlank alike the other validators
- Use of `assign` has been deprecated
- [rfc]: Externalize schema validation HOT 4
- Strange behavior with an array of objects HOT 2
- Dependent field validation capability
- Docs pages are missing
- `description` option type missing for validators
- Provided description for validation not passed in rawOutput for buildMessage
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ember-changeset-validations.