Looking for a library that could validate input like, for example:
{ points: array of { x: positive and < 20, y: positive and < 15 } }
Preferably working on both server and client side and returning a boolean or throwing an exception.
What I explicitly don't need is string or form validation, I just want to check if JSON sent by client is safe for processing without a ton of dispersed checks as I go.
You could also try Skematic.
Data structure and rule validation engine. Robust schema for JS objects.
It lets you design data models, then format and validate data against those models. Works in browser (Skematic global) or Node/io.js.
To solve your request, something basic like this should work:
// -- Define a simple data structure
var YourData = {
points: {
type:'array',
default: [],
schema: {
x: { type: 'number', required: true, rules: { min:0, max:20 } },
y: { type: 'number', required: true, rules: { min:0, max:15 } }
}
}
};
// -- Validate an object
Skematic.validate( YourData, {points:[ {x:-1,y:10} ]} );
// {valid:false,
// errors:{
// points: {0:{x:['Failed: min']}}
// }}
Never mind, wrote it myself.
https://bitbucket.org/virtulis/validata/overview
https://www.npmjs.org/package/validata
Related
The goal is to take model schema and export it somewhere as JSON, take that json and make a dynamic form in Angular.
Basically main problem which I see here is to get model, and generate output which will be important for generating reactive form in Angular.
For example:
module.exports = {
attributes: {
nameOnMenu: { type: 'string', required: true },
price: { type: 'string', required: true },
percentRealMeat: { type: 'number' },
numCalories: { type: 'number' },
},
};
So final output would look like:
[
{ nameOnMenu: { type: 'string', required: true }},
{ price: { type: 'string', required: true }},
{ percentRealMeat: { type: 'number', required: false }},
{ numCalories: { type: 'number', required: false }},
]
Based on this output, i will go through all and generate form.
I'm not sure that I really understand the question that you are asking here but let me take a bash at trying to provide an answer.
I can think of two ways that you could achieve it:
1.) Use server rendered local data to include the desired result for use on the front end.
2.) Make an API request from the front end for the desired result.
In your resulting controller/action you can get the model attributes in various ways. I can think of one:
const { resolve } = require('path');
// Portable relative path based on code being in
// config/bootstrap.js file so adjust as required
const modelDefinition = require(resolve(__dirname, '..', 'api', 'models', 'NameOfModel.js')).attributes;
console.log(modelDefinition);
{ name:
{ type: 'string',
required: true,
validations: { isNotEmptyString: true },
autoMigrations:
{ columnType: 'varchar(255)',
unique: false,
autoIncrement: false } },
...etc,
}
For completeness, you would need to factor in a few things regarding the model settings and model attributes in order to get an accurate output, for instance, whether or not the table includes an updatedAt field.
Ultimately, you can marshal this data as you see fit with vanilla Javascript/Node in order to obtain your desired result but I will leave that to you.
As another user has pointed out, I'm also not sure that you will find an officially supported solution for completely reactive data using Angular and Sails, I assume that this will require a bit of engineering in order for your to create something that is suitable for your needs.
I have a Dynamoose (DynamoDB) model called PromoCode with a schema that looks like this:
{
promoCode: {
hashKey: true,
type: String,
},
previouslyUsed: {
type: Boolean,
default: false,
index: {
global: true,
name: 'previouslyUsedIndex',
},
},
promoGroup: {
type: String,
index: {
global: true,
name: 'promoGroupIndex',
},
},
}
Essentially, I have a table full of promo codes and I want to get a single promo code that hasn't been used and is part of a particular "group" of promo codes.
So, I want to query on both previouslyUsed and promoGroup fields and limit the results to a single results. This is what I came up with:
PromoCode.query('previouslyUsed').eq(false)
.and()
.filter('promoGroup').eq('friend').limit(1)
This returns no results, even though I know that the query should match a result. If I increase the limit to 10, then I get back four results. This makes me think that the limit is happenning before the and() thus the preceding filter() is only filtering on the 10 returned results where previouslyUsed=false.
How do I take a single result where the conditions previouslyUsed=false and promoGroup=friend are valid?
So, here's what I figured out (to answer my own question). Firstly, using filter will only filter the results that are pulled from the database. So, I wasn't experiencing some weird bug.
Secondly, what I really wanted was a range key setup. This will give me the following schema:
{
promoCode: {
hashKey: true,
type: String,
},
previouslyUsed: {
type: Boolean,
default: false,
index: {
global: true,
name: 'previouslyUsedIndex',
rangeKey: 'promoGroup',
},
},
promoGroup: {
type: String,
rangeKey: true,
index: true,
},
}
Note the use of both instances of rangeKey above. Evidently both are necessary to do the following query:
PromoCode.query('previouslyUsed').eq(false)
.where('promoGroup').eq('friend')
It's actually as "simple" as that. This let's me filter on two different fields.
I am currently using the elasticsearch helper to run queries on my elasticsearch database. Currently I am using vue.js to help build this application.
When I am paginating my results I use this query:
this.client.search({
index: 'node',
type: 'vakantie',
from: 12 * index,
size: this.size,
}).then(function (resp) {
this.travels = resp.hits.hits;
this.currentPage = index;
}.bind(this), function (err) {
console.trace(err.message);
});
I also have an input box above my results that a user can type a search term into and it will instantly filter down results using this query:
index: 'node',
type: 'vakantie',
from: 0,
size: this.size,
body: {
query: {
match_phrase_prefix: {
title: {
query: this.query,
slop: 10,
max_expansions: 50
}
}
},
highlight: {
fields: {
title: {}
},
pre_tags: ["<span class='highlight'>"],
post_tags: ["</span>"]
}
}
I have filters and sort methods in place as well, and I know how to use a query with elasticsearch to combine multiple search queries.
Obviously I don't want to write a search query for every combination of filter + input + sort possible. Is there a better way to build up my search queries than using a javascript object like this?
Hopefully I am getting my point across, I have a bit too much custom code to simply paste it here.
I'm trying to use a custom validation function for a field defined in a simpleSchema, however the error message does not render on the field.
num: {
type: Number,
label: "Number",
min: 1,
decimal: false, // unnecessary as this is default for Number, but for future reference
autoform: {
group: "Info",
defaultValue: function() {
//#TODO - default to next number for logged in user
return 5;
}
},
custom: function () {
Collection.simpleSchema().namedContext("addNumberForm").addInvalidKeys([{name: "num", type: "numNotUnique"}]);
}
},
I've defined a custom error message for it
SimpleSchema.messages({numNotUnique: "This number has already been entered"});
When I submit the form I can confirm that the custom function executes, but nothing changes in the UI for that field indicating the error. The context name "addNumberForm" I got from the SimpleSchema.debug = true; setting and seeing what was thrown for other fields with default validation.
What am I missing here?
After much trial and error I've figured it out.
The simpleSchema named context is only necessary if manually validating using simpleSchema by itself. Autoform takes care of this, and the custom function can return a simple string that defines the error.
num: {
type: Number,
label: "Number",
min: 1,
decimal: false, // unnecessary as this is default for Number, but for future reference
autoform: {
group: "Info",
defaultValue: function() {
//#TODO - default to next number for logged in user
return 5;
}
},
custom: function () {
// some check
return 'numNotUnique'; // return our error
}
},
I use JQuery Validate to validate forms on my webapp. I can pass JQuery Validate a list of rules to use to validate my form like this:
$("#myform").validate({
rules: {
age: {
required: true,
min: 3
},
parent: {
required: function(element) {
return $("#age").val() < 13;
}
}
}
});
Now I would like to generate those validation rules on the server instead of coding them in my JavaScript, do an $.ajax request to get them, attach them to the form and be all set.
But this
{
rules: {
age: {
required: true,
min: 3
},
parent: {
required: function(element) {
return $("#age").val() < 13;
}
}
}
}
is not valid JSON, because there is the function declaration. Is there a way to do this?
To elaborate: my application is made of static HTML and JS, and my only interaction with the server is with some REST services that return JSON.
So when I get a person from the server because I want to edit it in a form, I do
$.ajax({url: '/person/1',
success: function(data) {
/* fill form fields */
...
/* get validation rules from server and attach to form
something like */
$.ajax({url: '/person/validation_rules',
success: function(rules) {
/* something like */
$('#myform').validate(rules);
}
}
});
Thanks.
How about simply returning it as a JS literal, instead of as JSON?
Edit:
Your original description included:
{
rules: {
age: {
required: true,
min: 3
},
parent: {
required: function(element) {
return $("#age").val() < 13;
}
}
}
}
That's a JS literal, not a JSON string, and is completely valid to return from the server, in and of itself. No additional changes necessary, and the function declaration is just fine. JSON is simply a subset of the JS literal. (http://www.json.org/js.html).
So, you could easily return that structure from your server, via some AJAX request, exactly as it is.
For more details: http://snook.ca/archives/javascript/json_is_a_subse
If you are already generating Javascript on the server, you don't need to load it as JSON. If you are loading this function from http://myserver.com/validation.js, instead of calling it with ajax, just call it from the script tag, eg.
<script src="http://myserver.com/validation.js"></script>
You will also need to edit slightly generated code:
var validationRule = {
rules: {
age: {
required: true,
min: 3
},
parent: {
required: function(element) {
return $("#age").val() < 13;
}
}
}
}
then your validation will look like
$("#myform").validate(validationRule);
EDIT: if server response must be JSON, you can get it as a string and eval() it. or you can arrange some valid json which you can tweak to desired form, say:
{
...
"minParentAge": 13
}
and then construct function from it.
Create a single global variable as your root namespace - just like third party libraries like jQuery do. Call it for instance MyNamespace.
Then load js files that populate this namespace, that way you get a minimal DOM footprint.
My preferred way is doing it like this:
<myFunctions.js>
MyNamespace = window.MyNamespace || {};
(function(){
function utilityFunction1() {
//....
}
function utilityFunction2() {
//....
}
MyNamespace.UtilityFunctions = {
utilityFunction1: utilityFunction1,
utilityFunction2: utilityFunction2
};
})();
</myFunctions.js>
then include it like always
<script src="myFunctions.js" type="text/javascript"></script>