Some questions on Simple-Schema for Meteor - meteor

For those who use Simple Schema for Meteor validation I've got some questions (after having used it for a while):
1.
Does SimpleSchema support square bracket notation? All the examples show it using dot notation. I did the following square bracket implementation:
Schemas.NamesCollection = new SimpleSchema({
name: {
type: Object
},
"name[first_name]" : {
type: String,
optional: false,
label: "First Name"
},
"name[last_name]" : {
type: String,
optional: false,
label: "Last Name"
}
});
{{> afQuickField name="name[first_name]"}}
{{> afQuickField name="name[last_name]"}}
I noticed that the form validation worked just fine as I'm filling out the form, but the final insertion of the data into the collection fails with a validation error (the same exact error that had passed earlier on the form validation but is now failing on insertion).
There are a lot of reasons to use square bracket notation, obviously. Dot notation has tons of limitations, despite being more readable.
2. Looking at the example above defining the schema, the keys in the schema have to be the full path in the object. You have to declare name[first_name] to assign a schema to it, which means that you're not only defining the properties of first_name, but you're also defining the structure of the object. first_name has to be nested inside name.
You can't, for example, just do
Schemas.NamesCollection = new SimpleSchema({
name: {
type: Object
},
first_name : {
type: String,
optional: false,
label: "First Name"
},
last_name : {
type: String,
optional: false,
label: "Last Name"
}
});
And then proceed to store first_name and last_name inside of name, can you?

Related

How do I reference another collection as a field in a Meteor Schema

I'm using meteor simple schema, and autoform. I would like to have a reference to one type of object in the schema of the other. The two schemas are defined in separate files, I would also like to populate autoform with a dropdown of the possible references, and I'm unclear how to do this.
I've tried
venue:{
type: Venues,
label: "Venue",
},
and
venue:{
type: SimpleSchema.Venues,
label: "Venue",
},
and neither works
First you have to define your schema like this:
VenueSchema = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
}
})
Than you can in another schema declare an attribute Venue
CustomerSchema = new SimpleSchema({
venue: {
type: VenueSchema
},
//an array of venues
venues: {
type: [VenueSchema],
minCount: 1
}
});
Take a look on basic usage of simpleSchema docs -> https://github.com/aldeed/meteor-simple-schema#basic-usage
I hope that helps.

Separate form validation with Meteor

I'm using collection2 and I'm trying to get it to handle validation is a specific way. I have a profile schema which looks kind of like this:
Schema.UserProfile = new SimpleSchema({
name: {
type: String,
optional: false
}
location: {
type: String,
optional: true
}
gender: {
type: String,
optional: false
}
});
Schema.User = new SimpleSchema({
username: {
type: String,
optional: true
},
emails: {
type: Array,
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
services: {
type: Object,
optional: true,
blackbox: true
},
roles: {
type: [String],
optional: true
},
heartbeat: {
type: Date,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Now, on my registration form I'm requiring the user to select their gender and then later once they log in, users are presented with a separate form asking for their name and location. Here's the problem:
The registration form works and everything goes through with saving. When they try to save the internal form with location and name though I get an error:
Error invoking Method 'updateProfile': Gender is required [400]
I know it's happening because it's required in the schema but I've already obtained this information. How do I not require that? Or do I set up validation per form?
You have to add validation through jquery or you can use toaster for display the error on client side.
Read this also : link
I assume you use aldeed:autoform for your forms. When you use normal type in the form, all fields, even those already filled marked as mandatory have to be submitted. Two ways to fix this:
Dirty way: set hidden field with the prefilled value.
You can also set your form type as update as seen in the doc. This way, simple-schema will validate your newDoc already filled with your previous entries without screaming.
The solution number two is the one I use in most cases. This plus autoform's hooks give you enough flexibility to adapt to most use-cases you might encounter.
I don't know whether or not it is a more elegant solution, but we've stopped attaching simpleSchemas to documents in our current project.
We instead have different schemas in each collection's namespace, one for checking user input on insert, one on update, and and one to be used to fill defaultValue when inserting a new doc (which can be done either by the client or the server, in which case we don't check for input). We call .validate() or .clean() depending on what we want to do.
With clever use of the possibility to build schemas from array of schemas, we're not writing bigger schemas in the end (there's more of them though), but we have total control on when we check, and which fields are checked.
From the SimpleSchema docs:
Say you have a required key "friends.address.city" but
"friends.address" is optional. If "friends.address" is set in the
object you're validating, but "friends.address.city" is not, there is
a validation error. However, if "friends.address" is not set, then
there is no validation error for "friends.address.city" because the
object it belongs to is not present.
So the error happens because you're including profile on both forms and gender is not optional within profile. I can think of two ways to solve this:
Have additional objects under profile that are both optional and contain required fields for name/location on one (though it seems like location might be optional in both scenarios based on your code) and a required field for gender on the other. I don't particularly like this solution but it prevents needing form validation.
Use jQuery form validation (I use the package themeteorchef:jquery-validation) and make all your fields in profile optional.
It also looks like SimpleSchema accepts a function for the optional property, so you could use some custom logic there - maybe you get arguments or a context in that function that will allow you to do what you want?
Hope that helps!

autoform won't render select option field

I have an issue regarding collection2 with relationships and autoform.
I try to implement an 1:n relationship, where each object has exactly 1 objectType, while to each objectType multiple objects can be referred to.
My schema looks as follows:
// register collections
Objects = new Mongo.Collection('objects');
ObjectTypes = new Mongo.Collection('objectTypes');
// define schema
var Schemas = {};
Schemas.ObjectType = new SimpleSchema({ // object type schema
name: {
type: String
}
});
Schemas.Object = new SimpleSchema({ // object schema
type: {
type: ObjectTypes.Schema,
optional: true
},
title: {
type: String
}
});
// attach schemas
ObjectTypes.attachSchema(Schemas.ObjectType);
Objects.attachSchema(Schemas.Object);
My autoform looks like this:
{{> quickForm collection="Objects" id="insertTestForm" type="insert"}}
I actually would expect a select option field for my type attribute, however, a text input appears. Anyone knows why?
According to the documentation [1], it should be a select option field:
If you use a field that has a type that is a Mongo.Collection instance, autoform will automatically provide select options based on _id and name fields from the related Mongo.Collection. You may override with your own options to use a field other than name or to show a limited subset of all documents. You can also use allowedValues to limit which _ids should be shown in the options list.
[1] https://github.com/aldeed/meteor-collection2/blob/master/RELATIONSHIPS.md#user-content-autoform
EDIT
If I use
type: ObjectTypes,
instead of
type: ObjectTypes.Schema,
my app crashes, throwing the following error:
Your app is crashing. Here's the latest log.
/Users/XXX/.meteor/packages/meteor-tool/.1.1.3.ik16id++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:245
throw(ex);
^
RangeError: Maximum call stack size exceeded
Exited with code: 8
Your application is crashing. Waiting for file change.
Your type isn't "a Mongo.Collection instance" like the documentation says; it's a Schema. Try this:
Schemas.Object = new SimpleSchema({
type: {
type: ObjectTypes,
optional: true
},
...
Since nobody could help me solve this incident, I came up with an alternate solution:
// register collections
Objects = new Mongo.Collection('objects');
ObjectTypes = new Mongo.Collection('objectTypes');
// define schema
var Schemas = {};
Schemas.Object = new SimpleSchema({ // object schema
type: {
type: String,
optional: true,
autoform: {
return ObjectTypes.find().map(function(c) {
return{label: c.name, value: c._id}
});
}
},
// ...
});
// attach schema
Objects.attachSchema(Schemas.Object);
As u can see, I manually map the attributes I need from the objectTypes collection into the autoform attribute. Since it returns an array of objects, containing the label and value attributes, autoform will automatically render a select option.

Meteor - Validations on structured data with simple schema / autoform

I'm have some simple schema which I'm using with autoform:
Schemas.studentRecord = new SimpleSchema({
'common.FName': { // note that this field is nested
type: String,
optional: false,
label: "First Name",
max: 50
}
});
Inserting a document using this schema works fine. Updating it does too. The problem is that when I'm nesting data the optional: false validation is not running, it's just ignored - meaning I can insert empty documents. However use the following schema without nesting it works:
Schemas.studentRecord = new SimpleSchema({
'commonFName': { // note that this field is no longer nested
type: String,
optional: false,
label: "First Name",
max: 50
}
});
So my question is, can I validate nested data or must I keep it unstructured for validation?
Solution was to include 'common' as part of the schema:
'common': {
type: Object
}

How to create AutoForm field in Meteor to select a record from another collection and save it as a subdocument?

I've been struggling with this for a couple of hours and I can't find a good solution so maybe someone can shed a light on this.
I have a simple schema like this:
var groupschema = new SimpleSchema({
name: {
label: 'Name',
type: String
},
description: {
label: 'Description',
type: String
}
}
And I have another one:
var itemschema = new SimpleSchema({
name: {
label: 'Type:',
type: String
},
details: {
label: 'Details',
type: String
},
group: [groupschema] // <--- this is my main interest
}
If I use the above code sample AutoForm will generate an "inner form" which is quite cool actually for some puporse (e.g. for a contact to have an array of adresses or phone numbers) but for me I would like a drop-down select with the name of the group and when I click on the Insert/Update button (depending on the current form) I would like to add the whole group document to the inserted/updated item document as a subdocument.
Something like this will be inserted to the mongodb:
{
_id: the generated mongoid,
name: "This is a type",
details: "There are some thing to know about this type",
group:{
name: "Cool group",
description: "This is a really cool group"
}
}
The actual documents are far more complicated the above example is just an oversimplified version.
I've stopped writing this question yesterday and tried to do my own version.
My - half baked - solution is:
introducing a new field in the schema named groupselect (type string, autoform type: select)
populate it's contents with a Collection.find().map() lookup
groupselect: {
type: String,
label: 'Group',
optional: true,
blackbox: true,
autoform:{
type: "select",
options : function() {
return Issuegroup.find().map(function (c) {
return {label: c.name , value: c._id};
});
}
}
},
using autoform hooks before insert I assign the subdocument to the real fiel group = Group.find({_id:doc.groupselect}) and I remove the helper field from the doc
using the same technique in the before update hook also for an update form
The problem I seem to be unable to solve in a clean way is to set the default value of the helper field 'groupselect' when the update form displays. I've tried the docToForm hooks but no luck.
Isn't this somehow a very common problem? I imagine there has to be a proper solution for this so I bet that I am missing something very obvious and hopefully someone will point it out for me.
Thanks

Resources