I am trying to get subschemas to work as an array, which I assume is the correct way to handle my problem (but please correct me if I am wrong!). I provide a simplified working example to show my problem, based on the BooksSchema example provided by the AutoForm package. In my example, I have a collection of Libraries, and one of the fields in the 'Libraries' object is supposed to be the library's collection of books. Rendering the AutoForm does not give me any input labels as defined in my Book collection, but instead just shows one (1) empty text input field.
Schemas:
import SimpleSchema from 'simpl-schema';
SimpleSchema.extendOptions(['autoform']);
BooksSchema = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
},
author: {
type: String,
label: "Author"
},
copies: {
type: Number,
label: "Number of copies",
min: 0
},
lastCheckedOut: {
type: Date,
label: "Last date this book was checked out",
optional: true
},
summary: {
type: String,
label: "Brief summary",
optional: true,
max: 1000
}
}, { tracker: Tracker });
LibrariesSchema = new SimpleSchema({
collection: {
type: Array
},
'collection.$': {
type: BooksSchema,
minCount: 1
}
});
LibrariesSchema.extend(BooksSchema);
Libraries = new Mongo.Collection("libraries");
Libraries.attachSchema(LibrariesSchema);
AutoForm:
{{> quickForm collection="Libraries" id="insertBookForm" type="insert"}}
Thank you so much in advance for your time, really been struggling with this for a long time now!
In my case I was indeed able to resolve the issue by using John Smith's example without the brackets.
LibrariesSchema = new SimpleSchema({
'books': {
type: BooksSchema,
minCount: 1
}
});
LibrariesSchema = new SimpleSchema({
'books': {
type: [BooksSchema],
minCount: 1
}
});
Arrays of a specific types, for use in check() or schema definitions, are specified as [SomeType], eg. [String], or [BooksSchema] in your case.
Related
I am new in meteor. I am using simple schema for quickForm and got this error.
Exception in template helper: TypeError: Cannot read property 'mergedSchema' of undefined
main.html
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
{{> quickForm collection="Books" id="bookUpdateForm" type="insert"}}
</template>
main.js
import './hello.html';
import { Books } from '../../../api/links/books.js';
Template.hello.onCreated(function () {
Meteor.subscribe('books');
});
Collection JS
import SimpleSchema from 'simpl-schema';
export const Books = new Mongo.Collection("books");
const Book = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
},
author: {
type: String,
label: "Author"
},
copies: {
type: SimpleSchema.Integer,
label: "Number of copies",
min: 0
},
lastCheckedOut: {
type: Date,
label: "Last date this book was checked out",
optional: true
},
summary: {
type: String,
label: "Brief summary",
optional: true,
max: 1000
}
});
Books.attachSchema(Book);
There is a typo that causes a follow up error. You collection is namen "books" but you pass "Books" to your quickForm. Because AutoForm cannot find any collection named "Books" in global scope it will throw an error.
This approach also assumes Books to be in window scope.
If you are new to JS, then you may first read about scopes and window scope:
https://developer.mozilla.org/en-US/docs/Glossary/Scope
https://developer.mozilla.org/en-US/docs/Web/API/Window
Why are global variables considered bad practice?
Less error prone pattern
An alternative approach would be to import Books to your template (as you have already done) and provide it to quickForm via a Template helper:
main.html
<template name="hello">
{{> quickForm collection=getCollection id="bookUpdateForm" type="insert"}}
</template>
Note getCollection which is basically calling a helper you define in your Template helpers section:
main.js
import './hello.html';
import { Books } from '../../../api/links/books.js';
Template.hello.onCreated(function () {
Meteor.subscribe('books');
});
Template.hello.helpers({
getCollection() {
return Books;
}
});
By doing so you have a) avoided window (global) scope and b) avoided errors due to spelling errors, because you pass the reference to the collection directly to the quickForm.
Collection JS
import SimpleSchema from 'simpl-schema';
export const Books = new Mongo.Collection("books");
const Book = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
},
author: {
type: String,
label: "Author"
},
copies: {
type: SimpleSchema.Integer,
label: "Number of copies",
min: 0
},
lastCheckedOut: {
type: Date,
label: "Last date this book was checked out",
optional: true
},
summary: {
type: String,
label: "Brief summary",
optional: true,
max: 1000
}
});
Books.attachSchema(Book);
I am trying to build a kind of specific simple schema for a collection and i would like to make sure that :
when the user enter a new select in my selectsCollection, he will put one of the options value as selected value.
For example:
SelectsCollection.insert({name:"SelectOne",deviceType:"Select",options:["option1","option2","option3"],value:"option4",description:"This is the first select"});
this do not have to work. I want him to write only one of the 3 options.
Here my schema :
SelectsCollection = new Mongo.Collection('Selects'); //Create a table
SelectsSchema = new SimpleSchema({
name:{
type: String,
label:"Name",
unique:true
},
deviceType:{
type: String,
allowedValues: ['Select'],
label:"Type of Device"
},
options:{
type: [String],
minCount:2,
maxcount:5,
label:"Select Values"
},
value:{
type: String,
//allowedValues:[options] a kind of syntax
// or allowedValues:function(){ // some instructions to retrieve the array of string of the option field ?}
label:"Selected Value"
},
description:{
type: String,
label:"Description"
},
createdAt:{
type: Date,
label:"Created At",
autoValue: function(){
return new Date()
}
}
});
SelectsCollection.attachSchema(SelectsSchema);
Any Idea ? :)
Thanks a lot !
This could be done with custom validation function of a field, inside this function you could retrieve values from other fields:
SelectsSchema = new SimpleSchema({
// ...
options: {
type: [String],
minCount: 2,
maxcount: 5,
label: "Select Values"
},
value: {
label: "Selected Value",
type: String,
optional: true,
custom() {
const options = this.field('options').value
const value = this.value
if (!value) {
return 'required'
}
if (options.indexOf(value) === -1) {
return 'notAllowed'
}
}
},
// ...
});
Look here custom-field-validation for more information
I created two seperate schemas for payments collection and memberProfile. Now I need to create a quickform so I could load all the payments relevant to a unique memberProfile.
//The code for memberPayment collection
MemberProfiles = new Mongo.Collection('memberProfiles');
RecipeSchema = new SimpleSchema({
name: {
type: String,
label: "Name"
},
desc: {
type: String,
label: "Description"
},
payments:{
type: [PaymentSchema],
autoValue: function () {
return Payments.find({ memberId="uniqueId"});
},
defaultValue: function () {
return Payments.find({memberId="uniqueId"});
},
},
// The code for payments collection
PaymentSchema = new SimpleSchema({
name:{
type: String
},
amount:{
type: String
},
memberId:{
type: String
},
});
This code doesn't work.
Looks like you're missing the schema attribute. Any autoform needs to take in a schema attribute that explicitly tells autoform to use that schema to generate the necessary form. Check this page out for demos using autoform.
{{> quickForm collection="theMongoCollection" id="theFormID" schema="theSchemaName" type="typeOfForm" }}
I have a schema like so (fluff cut out):
Schemas.people = new SimpleSchema({
note: {
type: [Schemas.notes],
optional: true,
defaultValue: []
},
updates: {
type: [Schemas.updates],
optional:true,
autoValue:function(){
if (this.isInsert) {
return [{
at: new Date,
user_id: this.userId
}];
}
return {
$push:{
at: new Date,
user_id: this.userId
}
}
}
}
});
And the notes schema looks like:
Schemas.notes = new SimpleSchema({
note: {
type: String,
autoform: {
afFieldInput:{
type:"textarea"
}
},
optional: true
},
updates: {
type: [Schemas.updates],
optional:true,
autoform:{
omit:true
},
autoValue:function(){
if (this.isInsert) {
return [{
at: new Date,
user_id: this.userId
}];
}
return {
$push:{
at: new Date,
user_id: this.userId
}
}
}
}
});
And the updates schema is super simple:
Schemas.updates = new SimpleSchema({
at: {
type: Date
},
user_id:{
type: Meteor.ObjectID
}
});
The "updates" field on the people schema saves the date/user id as expected when an update is made. However, it fails on the notes schema:
SimpleSchema invalid keys for "blablabla" context:
0: Object
name: "note.0.updates.0.at"
type: "keyNotInSchema"
value: Mon May 11 2015 11:57:58 GMT-0400 (Eastern Daylight Time)
1: Object
name: "note.0.updates.0.user_id"
type: "keyNotInSchema"
value: "abcd1234"
I believe that the "name" should look like "people.note.0.updates.0.at" but I'm unsure that this assumption is correct and I'm completely unsure how to go about making that happen.
Update:
Code used to update people
{{#autoForm collection="people" id=formId type="update" class="update" autocomplete="off" doc=getDocument autosave=true template="quickform"}}
{{> afQuickField name='note' template="quickform" }}
{{/autoForm}}
formId returns a randomish ID string and getDocument passes in the correct collection.
Schemas.notes._schemaKeys does not list the at and user_id fields... but Schemas.people._schemaKeys does.
People schema shows: [..., "updates.$.at", "updates.$.user_id", ...]
Notes schema shows: ["note", "updates", "updates.$"]
How bizarre.
Note that Meteor uses standard JavaScript syntax and therefore has the same restrictions, for example as you already realized order of code is important.
Let's have a look.
Schemas.notes = new SimpleSchema({
updates: {
type: [Schemas.updates]
}
}
There are no nested functions in this code, therefore every code of line will be executed, before Meteor continues with the next Schema definition. Schema.updates will be dereferenced immediately, although it isn't set yet. type will be an array containing null and that finally makes SimpleSchema assume that no fields are allowed at all.
The issue is with the order in which the schemas are declared. Which I suppose makes sense? I was declaring "notes" before "updates", and "people" last. Putting "updates" first fixed the issue completely.
I'm going to report this as a possible bug to the collection repo.
I made some auto form code
Problem is
autoValue: ->
#_id
is not work..
form are made but not sumited
do you guys know why?
Comments.insert
createAt: new Date
body: tmpl.find('textarea#com').value
todoId: #_id
#Comments = new Mongo.Collection('comments')
Comments.attachSchema new SimpleSchema
comments:
type: String
max: 100
label: 'CommentsBody'
commentsId:
label: 'CommentsId'
type: String
autoValue: ->
#_id
autoform:
omit: true
Your schema and your insert method does not match. Also, doing an autovalue -> #_id is redundant as it will save _id twice, once in the _id field and once in the commentsId.
This is the schema that should work with your method:
Comments.attachSchema new SimpleSchema
body:
type: String
max: 100
label: 'CommentsBody'
createAt:
type: Date
autoValue: ->
if #isInsert
new Date()
autoform:
omit: true
todoId:
type: String