I have implemented a custom validation function using the example referenced in the SimpleSchema documentation for validating the uniqueness of a username. In the example, an asynchronous call is made and a custom validation message is displayed if the username is found to already exist.
There is a note, that indicates that if all of the form fields are valid, the form will be submitted, however user creation will fail due to the "unique: true" requirement specified in the schema. Here is the relevant portion of the code from the example docs:
username: {
type: String,
regEx: /^[a-z0-9A-Z_]{3,15}$/,
unique: true,
custom: function () {
if (Meteor.isClient && this.isSet) {
Meteor.call("accountsIsUsernameAvailable", this.value, function (error, result) {
if (!result) {
Meteor.users.simpleSchema().namedContext("createUserForm").addInvalidKeys([{name: "username", type: "notUnique"}]);
}
});
}
}
}
In my case, I have the code working where I am testing if an activation code is valid, I even get the interface to display the error, however since there is no other "schema" failure, the form submits, despite the invalid response... do I need to manually prevent form submission (i.e. using jQuery), or is there something in SimpleSchema I should use instead?
activationCode: {
type: String,
label: "Activation Code",
max: 200,
min: 10,
regEx: /^(?=.*[A-Z])(?=.*\d).+$/,
custom: function() {
if (Meteor.isClient && this.isSet) {
Meteor.call("validateActivationCode", this.value, function(error, result) {
if (result && !result.isValid) {
Clients.simpleSchema().namedContext("signupForm").addInvalidKeys([{
name: "activationCode",
type: "notValid"
}]);
return false;
}
});
}
}
}
Thank You
Related
http://hapijs.com/tutorials/validation
I'd like to pass a function in to my validation block that checks for the presence of v as a source and confirms that account, profile and ipAddress are present. The docs say this is possible but don't have an example of using a function var to do it.
When I start up my API I get: Error: Invalid schema content: (account)
How can I use a named function to do validation in Hapi?
Code:
var validateQueryString;
validateQueryString = function(value, options, next) {
console.dir({
value: value,
options: options
});
// do some validation here
return next(null, value);
};
routes.push({
method: 'POST',
path: '/export/{source}/{start}/{end?}',
config: {
validate: {
query: {
account: validateQueryString,
profile: validateQueryString,
ipAddress: validateQueryString
},
params: {
source: joi.string().valid(['a', 'v', 't']),
start: joi.string().regex(utcDateTimeRegex),
end: joi.string().regex(utcDateTimeRegex)
}
}
},
handler: function(apiRequest, apiReply) {}
});
Tried other ways of calling this like:
account: function(value, options, next) {
return validateQueryString(value, options, next); }
with no luck.
I don't think you can have a single function to handle both at the same time.
Typically, the method for the full 'list' of query parameter. Here is a bit of code to illustrate:
function validateQuery(value, options, next){
console.log( 'validating query elements');
for (var k in value) {
console.log( k, '=', value[k]);
}
next(new Error(null, value);
}
And you set it as follow:
routes.push({
...
validate: {
query: validateQuery,
params: ...
}
...
}
Now, let's assume you hit http://server/myroute?a=1&b=2&c=3, you will get the following output:
validating query elements
a = 1
b = 2
c = 3
If you want to throw an error, you have to call next() as follow:
next( new Error('some is wrong'), value );
So the 'proper' way is to have a method for query and params, it seems.
Hope this helps.
I would recommend what you are doing is out of bounds of Joi's intent. Joi is targetted for schema validation against a JS object. What you want is runtime validation against rules that exist outside of the schema itself. Hapi has something built for this called server method. Leveraging server methods, you can apply your business validations there while separating the concerns of input model and output model shape validation through Joi.
I am trying to implement a custom validator for a paper-input. In this particular case, the control should accept positive numbers. However, not only only will the control only accept positive numbers, it will also run some other custom validation logic to determine if the entry falls within a constantly changing (dynamic & calculated) upper and lower limit. Ideally, the paper-input control's error-message text will also change depending on what part of the custom validator check failed.
In the past, I was able to implement this sort of thing with the gold-email-input element. In that case, the control checks for an entry that matches a regular expression for email addresses (i.e. implements a type-check). It also calls a backend api to see if the email address entered (as it is being typed), already exists in a database. If it exists in the database, the control fails validation and updates the control's validation error-message with a custom message. If it does not exist, it passes validation. As you might have imagined by this description, this was for a user registration UI element whereby the provided email should not already exist in the current list of user accounts. Here is an excerpt of that working code below for your reference:
<gold-email-input id="userEmail" label="Email" required auto-validate value="{{userEmail}}" error-message$="{{_getEmailErrorMsg(0)}}" invalid="{{_emailInvalid}}" validator="_validateEmail"></gold-email-input>
<iron-signals on-iron-signal-email-used="_accountFound" on-iron-signal-email-available="_accountNotFound"></iron-signals>
<script>
var emailErrors = ["Provide a valid email address", "Address already used"];
// Register the polymer element
Polymer({
properties: {
userEmail: {type: String, value: null},
validated: {type: Boolean, notify: true}, //overall validity state of entire element
_emailInvalid: {type: Boolean, value: true, observer: "_validityChanged"}, // validity state of email input itself
},
ready: function() {
// Called before attached
this.$.userEmail.validate = this._validateEmail.bind(this);
},
_accountFound: function() {
// Listener function intended to fire when the user email address/account was found
console.log(this.nodeName + " accountFound listener called\n");
this.$.userEmail.errorMessage = this._getEmailErrorMsg(1);
this._emailInvalid = true;
},
_accountNotFound: function() {
// Listener function intended to fire when the user email address/account was not found
console.log(this.nodeName + " accountNotFound listener called\n");
this.$.userEmail.errorMessage = this._getEmailErrorMsg(0);
this._emailInvalid = false;
},
_checkAccountExistance: function() {
if (this.userEmail !== undefined && this.userEmail != null) {
this.$.user.checkEmailAvailability(this.userEmail);
} else {
this._emailInvalid = true;
}
},
_getEmailErrorMsg: function(code) {
if (code !== undefined && code != null) {
return emailErrors[code];
} else {
return "";
}
},
_validateEmail: function() {
// Custom validator function for email input (also checks if email has already been associated to any user accounts)
console.log(this.nodeName + " validateEmail validator called\n");
// Check if proper email address format (W3C Spec Regex used)
var validEntry = /^[a-zA-Z0-9.!#$%&�*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(this.userEmail);
if (validEntry) {
this._emailInvalid = false;
this._checkAccountExistance();
} else {
this._emailInvalid = true;
}
}
_validityChanged: function(newVal, oldVal) {
// set the containing/parent element's overall validity state
this.validated = (!this._nameInvalid && !this._pwInvalid && !this._phoneInvalid && !this._emailInvalid && !this._countryInvalid && !this._regionInvalid && !this._cityInvalid);
},
});
</script>
Now, if I try to implement a similar approach with the paper-input component, it does not work. The custom validator function does not get called at any point. Is there something inherently different with paper-input compared to gold-email-input? Should it not treat validation the same way?
<paper-input id="xpos" label="Horizontal Position" required auto-validate value="{{XPos}}" error-message="Provide the x position" invalid="{{_xInvalid}}" validator="_validatePosition"></paper-input>
<script>
// Register the polymer element
Polymer({
properties: {
xPos: {type: Number},
validated: {type: Boolean, notify: true}, //overall validity state of entire element
_xInvalid: {type: Boolean, value: true, observer: "_validityChanged"}, // validity state of xpos input itself
},
ready: function() {
// Called before attached
this.$.xpos.validate = this._validatePosition.bind(this);
},
_validatePosition: function() {
console.log(this.nodeName + " validatePosition validator called\n");
// perform some validation code here like the gold-email-input example above
}
});
</script>
I have a "post"-model in strongloop loopback with some properties:
title
text
tags
category
published (true or false)
Is it possible to use the model validations in strongloop loopback, but only when I want to publish the post, not when I save it?
Set up a custom post.saveOrPublish() remote method that only calls post.isValid() when post.publish === true. Or use the built-in persistedModel.save() for everything without validation and use a custom post.publish() remote method for when you actually click the publish button, which would trigger your validation code before calling save().
saveOrPublish example: (not tested, just a rough idea):
module.exports = function(Post) {
Post.saveOrPublish = function(post, cb) {
if(post.publish) {
post.isValid(function(valid){
if(valid) {
Post.upsert(post, function(err, post) {
if(err) {cb(err, null);}
cb(null, post);
});
} else {
cb(new Error('Publishing requires a valid post.'), post)
}
});
} else {
Post.upsert(post, function(err, post) {
if(err) {cb(err, null);}
cb(null, post);
});
}
};
// don't forget the remote method def
Post.remoteMethod('saveOrPublish',
{
accepts: [{
arg: 'post',
type: 'object'
}],
returns: {
arg: 'result',
type: 'object'
},
http: {verb: 'post'}
}
);
};
I am using ember-validations to validate a model in a form.
If I create the record with createRecord the instance of the model is already validated and therefore the form already shows validations errors before the user inputs values.
I just want to validate the model before submitting the form. Is there a way?
You need to add a conditional validator ('if' or 'unless') and activate it only when submitting the form.
Here is a quick example: http://jsbin.com/letujimu/1/edit?html,js,output
There is another alternative to ember-validations. ember-model-validator, with this addon you decide when to validate. By including Ember-model-validator's mixin into your model, this will add a validate function to your model, it is a synchronous function which returns either true or false.
There is support for all these validations:
Presence
Acceptance
Absence
Format
Length
Email
Color
ZipCode
Subdomain
URL
Inclusion
Exclusion
Numericality
Match
Password
CustomValidation
Relations
Example:
// Your model
import Validator from '../mixins/model-validator';
export default DS.Model.extend(Validator, {
email: DS.attr('string'),
password: DS.attr('string'),
passwordConfirmation: DS.attr('string'),
validations: {
email: {
presence: true,
email: { message: 'is not a valid email' }
},
password: {
presence: true,
length: {
minimum: 6
}
},
passwordConfirmation: {
presence: true,
match: 'password'
}
}
});
import Ember from 'ember';
export default Ember.Route.extend(
{
actions: {
saveFakeModel: function() {
var _this = this,
fakeModel = this.get('model');
if(fakeModel.validate()){
fakeModel.save().then(
// Success
function() {
// Alert success
console.log('ooooh yeah we just saved the FakeModel...');
},
// Error handling
function(error) {
// Alert failure
console.log('There was a problem saving the FakeModel...');
console.log(error);
}
);
}else{
fakeModel.get('errors');
}
},
}
}
);
I have a simple registration form using Jquery mobile & jquery-validate.
If the user enters a correct username and password, I redirect them to their dashboard.
If they miss a field the client side validation picks it up.
My problem is when the server side validation rejects the user registration.
For example the user name is all ready taken.
In this case I render the page on the server with an error message.
On the client side I see the original page transition out and the new page transition in.
The new page has the error message displayed correctly.
How ever my script to init the client side validation does not take effect.
My guess is that there are two elements with the same id on the page at the same time.
So the old one gets the validation run on it again and is then transitioned away.
How do I handle this?
Here is the script
$('#registerPage').live('pagecreate', function (event) {
$("#registerForm").validate({
rules: {
username: "required",
password: "required",
confirmPassword: {
required: true,
equalTo: "#password"
}
}
});
});
Fixed it by using the new page as the context for the validation selector.
var rps = rps || {};
rps.register = rps.register || {};
rps.register.validate = function (context) {
$("#registerForm", context).validate({
rules: {
username: "required",
password: "required",
confirmPassword: {
required: true,
equalTo: "#password"
}
}
});
};
$(document).on('pageshow', '#registerPage', null, function (event, ui) { rps.register.validate(); });
$(document).on('pagehide', '#registerPage', null, function (event, ui) { rps.register.validate(ui.nextPage); });