Closed ZhuQinglei closed 7 years ago
MessageBox.defaults()
or the specific schema's messagebox with instance.messageBox.messages()
with the wrongPassword
code you provided before:
import MessageBox from 'message-box';
MessageBox.defaults({
en: {
wrongPassword: "Wrong password"
}
})
Then add a custom()
validation error (like here) to your Schema
that can throw your newly added error code:
custom: function () {
var reg = new RegExp('ab+c'); //Your custom regular expression
if (!reg.test(this.value)) {
return "wrongPassword";
}
}
4. These packages are newish and @aldeed working hard on it for us. So the documentations and functionalities can be a bit confusing 😄
5. `Schema.messageBox` is NOT (yet #77) global ([connecting issue for the same problem](https://github.com/aldeed/node-message-box/issues/6)). The documentation is wrong in that case. You can only get / set it for singular `SimpeSchema` instances.
The included `MessageBox.defaults` code you provided contains `simpl-schema` specific `regExpObj` and `regExpMessages` so it won't work because of that.
@Szayet Thank you soooooo much for the help and reply!!
According to your instruction, I can call the custom validation method and get return value as I expected, however, the validation error message is not passed to client side to display.
Here is my code in imports/Users.js:
MessageBox.defaults({
en: {
EmailNotUnique: "The email address is already taken"
}
});
Meteor.users.schema = new SimpleSchema({
_id: {type: String, optional: true},
emails: {type: Array},
'emails.$': {type: Object, label: 'Email'},
'emails.$.address': {
type: String, label: 'Email', max: 255, regEx: SimpleSchema.RegEx.Email,
custom() {
if (Meteor.isClient && this.isSet) {
Meteor.call("accountsIsEmailAvailable", this.value, (error, result) => {
console.log(error, result);
if (result) {
this.validationContext.addValidationErrors([{
name: "email",
type: "EmailNotUnique"
}]);
}
});
}
}
},
'emails.$.verified': {type: Boolean},
createdAt: {type: Date, optional: true},
services: {type: Object, blackbox: true, optional: true},
username: {type: String, optional: true},
profile: {type: UserProfile, optional: true},
});
the meteor mtd 'accountsIsEmailAvailable ' is using Accounts.findUserByEmail(email) in Accounts package and returns the user obj if it finds the email already existing in db.
And here is my console log and message print at client side:
I can see that the custom function is called async at end of my redux dispatch error messages. But I would like to add this email error to the client side for displaying, do you have any suggestion on that?
Yes, I fully understand that the package is still newish and it is difficult to manage so many useful & popular packages at the same time! Really appreciate all your hard work and the convenience that @aldeed 's packages offer.
@ZhuQinglei No problem, I'm glad it helped. 😄
To display async
validation errors, you have to use Tracker
support. Here is the relevant part of the documentation.
import { Tracker } from 'meteor/tracker';
new SimpleSchema({
....
}, { tracker: Tracker });
Then your ValidationContext#validationErrors
should rerun if placed inside a Tracker
watched part. (like in the linked example above). To save the hassle aldeed:autoform forms can handle this kind of error display which package I higly recommend using. That package's documentation also points out to pass the Tracker.
@Szayet Thank you for helping. I followed your comments to get me out of a tough spot. Though my code is working now, I just cant get the error message to display the correct message. Please check my code and tell me where I am going wrong.
> MessageBox.defaults({
> en: {
> ShareLimitExceeded: "Number of shares issued cannot exceed share cap"
> }
> });
>
> Shares.schema = new SimpleSchema({
> description: {
> type: String,
> label: 'Share Description',
> max: 1000,
> min: 1,
> },
> issuedShares: {
> type: Number,
> label: 'Shares to Issue',
> min: 1,
> custom: function () { // call a server method to compare this value against sharecap
> if (Meteor.isClient) {
> Meteor.call("ShareBank.methods.shareCapExceeded", this.value, (error, result) => {
> console.log(error, result);
> if (error) {
> this.validationContext.addValidationErrors([{
> name: "issuedShares",
> type: "ShareLimitExceeded"
> }]);
> }
> });
> }
> }
> },
I keep getting "issuedShares is invalid" as error message instead of "Number of shares issued cannot exceed share cap" as required from
ShareLimitExceeded: "Number of shares issued cannot exceed share cap"
@nosizejosh Hello, recently I fall into the same problem. And I have solved it in fork way. link
Maybe it can helps somebody.
I had a similar problem, I wanted to replace the built-in errors with translated versions:
import SimpleSchema from 'simpl-schema'
import MessageBox from 'message-box'
import { Tracker } from 'meteor/tracker'
const mySchema = new SimpleSchema({
...
}, {tracker: Tracker})
// this domain regex matches all domains that have at least one .
// sadly IPv4 Adresses will be caught too but technically those are valid domains
// this expression is extracted from the original RFC 5322 mail expression
// a modification enforces that the tld consists only of characters
const rxDomain = '(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z](?:[a-z-]*[a-z])?'
// this domain regex matches everythign that could be a domain in intranet
// that means "localhost" is a valid domain
const rxNameDomain = '(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.|$))+'
// strict IPv4 expression which allows 0-255 per oktett
const rxIPv4 = '(?:(?:[0-1]?\\d{1,2}|2[0-4]\\d|25[0-5])(?:\\.|$)){4}'
// strict IPv6 expression which allows (and validates) all shortcuts
const rxIPv6 = '(?:(?:[\\dA-Fa-f]{1,4}(?::|$)){8}' // full adress
+ '|(?=(?:[^:\\s]|:[^:\\s])*::(?:[^:\\s]|:[^:\\s])*$)' // or min/max one '::'
+ '[\\dA-Fa-f]{0,4}(?:::?(?:[\\dA-Fa-f]{1,4}|$)){1,6})' // and short adress
// this allows domains (also localhost etc) and ip adresses
const rxWeakDomain = `(?:${[rxNameDomain, rxIPv4, rxIPv6].join('|')})`
const regExpObj = {
// We use the RegExp suggested by W3C in http://www.w3.org/TR/html5/forms.html#valid-e-mail-address
// This is probably the same logic used by most browsers when type=email, which is our goal. It is
// a very permissive expression. Some apps may wish to be more strict and can write their own RegExp.
Email: /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
// Like Email but requires the TLD (.com, etc)
EmailWithTLD: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[A-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[A-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?$/,
Domain: new RegExp(`^${rxDomain}$`),
WeakDomain: new RegExp(`^${rxWeakDomain}$`),
IP: new RegExp(`^(?:${rxIPv4}|${rxIPv6})$`),
IPv4: new RegExp(`^${rxIPv4}$`),
IPv6: new RegExp(`^${rxIPv6}$`),
// URL RegEx from https://gist.github.com/dperini/729294
// http://mathiasbynens.be/demo/url-regex
Url: /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a>
// unique id from the random package also used by minimongo
// character list: https://github.com/meteor/meteor/blob/release/0.8.0/packages/random/random.js#L88
// string length: https://github.com/meteor/meteor/blob/release/0.8.0/packages/random/random.js#L143
Id: /^[23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz]{17}$/,
// allows for a 5 digit zip code followed by a whitespace or dash and then 4 more digits
// matches 11111 and 11111-1111 and 11111 1111
ZipCode: /^\d{5}(?:[-\s]\d{4})?$/,
// taken from Google's libphonenumber library
// https://github.com/googlei18n/libphonenumber/blob/master/javascript/i18n/phonenumbers/phonenumberutil.js
// reference the VALID_PHONE_NUMBER_PATTERN key
// allows for common phone number symbols including + () and -
Phone: /^[0-90-9٠-٩۰-۹]{2}$|^[++]*(?:[-x‐-―−ー--/ <200b> ()()[].\[\]/~⁓∼ ~*]*[0-90-9٠-٩۰-۹]){3,}[-x‐-―−ー--/ <200b> ()()[].\[\]/~⁓∼ ~0-90-9٠-٩۰-۹]*(?:ext=([0-90-9٠-٩۰-۹]{1,7})|[ \t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xx##~~]|int|anexo|int)[:\..]?[ \t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)?$/i, // eslint-disable->
}
const regExpMessages = [
{ exp: regExpObj.Email, msg: 'muss eine gültige Email-Adresse sein' },
{ exp: regExpObj.EmailWithTLD, msg: 'muss eine gültige Email-Adresse sein' },
{ exp: regExpObj.Domain, msg: 'muss eine gültige Domain sein' },
{ exp: regExpObj.WeakDomain, msg: 'muss eine gültige Domain sein' },
{ exp: regExpObj.IP, msg: 'muss eine gültige IPv4 or IPv6-Adresse sein' },
{ exp: regExpObj.IPv4, msg: 'muss eine gültige IPv4-Adresse sein' },
{ exp: regExpObj.IPv6, msg: 'muss eine gültige IPv6-Adresse sein' },
{ exp: regExpObj.Url, msg: 'muss eine gültige URL sein' },
{ exp: regExpObj.Id, msg: 'muss eine gültige alphanumerische ID sein' },
{ exp: regExpObj.ZipCode, msg: 'muss eine gültige Postleitzahl sein' },
{ exp: regExpObj.Phone, msg: 'muss eine gültige Telefonnummer sein' },
]
const myMessageBox = new MessageBox({
initialLanguage: 'de',
messages: {
de: {
required: '{{label}} wird benötigt',
minString: '{{label}} muss mindestends {{min}} Buchstaben lang sein',
maxString: '{{label}} darf nicht mehr als {{max}} lang sein',
minNumber: '{{label}} muss mindestens {{min}} sein',
maxNumber: '{{label}} darf nicht größer als {{max}} sein',
minNumberExclusive: '{{label}} muss größer als {{min}} sein',
maxNumberExclusive: '{{label}} muss kleiner als {{max}} sein',
minDate: '{{label}} muss {{min}} oder später sein',
maxDate: '{{label}} kann nicht nach {{max}} sein',
badDate: '{{label}} ist kein gültiges Datum',
minCount: 'Du musst mindestens {{minCount}} Werte angeben',
maxCount: 'Du darfst nicht mehr als {{maxCount}} Werte angeben',
noDecimal: '{{label}} muss eine ganze Zahl sein',
notAllowed: '[value] ist kein erlaubter Wert',
expectedType: '{{label}} muss vom Typ {{dataType}} sein',
regEx({ label, regExp }) {
// See if there's one where exp matches this expression
let msgObj
if (regExp) {
msgObj = _.find(regExpMessages, (o) => o.exp && o.exp.toString() === regExp)
}
const regExpMessage = msgObj ? msgObj.msg : 'Die Eingabe wurde bei der Überprüfung durch einen regulären Ausdruck für ungültig erklärt'
return `${label} ${regExpMessage}`
},
keyNotInSchema: '{{name}} ist nicht im Schema vorgesehen'
}
}
})
mySchema.messageBox = myMessageBox
Most code is taken from the messagebox defaults. Obviously you should put that messagebox in a file somewhere and import it always when you need it.
I wonder how this works: https://github.com/aldeed/node-simple-schema/blob/2b8f902e0d8d84eb923f9cf0cca2124f03f41cf8/lib/testHelpers/testSchema.js#L171
https://github.com/aldeed/node-simple-schema#customizing-validation-messages
This was not very well documented until yesterday, but I'm pretty sure there's no actual issue here. If I'm wrong, I can reopen this.
@aldeed I am using this for my meteor project and I have migrate from meteor package to this node_module package together with collection-2-core package.
Currently I want to customize the validation messages for regEx because all error message for regEx is just "failed regular expression validation", and I would like to give a more clear validation message such as "must contain at least 1 digit" etc.
However, I couldn't find a correct way/clear example to do it. I checked the message-box package and still don't know how to do it, and I found the documentation a bit confusing :
import MessageBox from 'message-box';
should be included in the Usage.MessageBox.defaults({ initialLanguage: 'en', messages: { en: { required: '{{label}} is required', minString: '{{label}} must be at least {{min}} characters', maxString: '{{label}} cannot exceed {{max}} characters', minNumber: '{{label}} must be at least {{min}}', maxNumber: '{{label}} cannot exceed {{max}}', minNumberExclusive: '{{label}} must be greater than {{min}}', maxNumberExclusive: '{{label}} must be less than {{max}}', minDate: '{{label}} must be on or after {{min}}', maxDate: '{{label}} cannot be after {{max}}', badDate: '{{label}} is not a valid date', minCount: 'You must specify at least {{minCount}} values', maxCount: 'You cannot specify more than {{maxCount}} values', noDecimal: '{{label}} must be an integer', notAllowed: '{{value}} is not an allowed value', expectedType: '{{label}} must be of type {{dataType}}', regEx: function ({ label, type, regExp, }) { console.log(label, type, regExp) // See if there's one where exp matches this expression let msgObj; if (regExp) { msgObj = _.find(regExpMessages, (o) => o.exp && o.exp.toString() === regExp);
});