Attaching multiple schemas to same collection using autoform and collection2 - meteor

I have two forms and two schema that don't have anything in common. But I still need them to be stored in the same collection.
Eg.:
schema1 = new SimpleSchema({ field1, field2, field3 });
collection.attachSchema(schema1);
schema2 = new SimpleSchema({ fieldX, fieldY, fieldZ });
collection.attachSchema(schema2);
From Collection2 documentation it is understood that the above method will actually merge both the schema into a single big schema. This means that both form must have all fields belonging to both schema.
This means that I can't have an autoForm with just schema1 and another autoform with just schema2.
As per the documentation, I tried implementing replace: true - by which, the schema gets overwritten each time. ( At least this is how I understand it - they don't get merged into a big schema)
Eg:
schema1 = new SimpleSchema({ field1, field2, field3 });
collection.attachSchema(schema1, {replace: true});
schema2 = new SimpleSchema({ fieldX, fieldY, fieldZ });
collection.attachSchema(schema2 {replace: true});
The above still does not fix the issue and Somehow, the schemas still get merged. Meaning, I still get notified that FieldX is blank in autoform1 even though there is no provision for fieldX to be filled.
I Also tried the other approach where in you use variations.
Eg.:
schema1 = new SimpleSchema({ field1, field2, field3 });
collection.attachSchema(schema1, {selector: {type: 'forForm1'}});
schema2 = new SimpleSchema({ fieldX, fieldY, fieldZ });
collection.attachSchema(schema2, {selector: {type: 'forForm2'}});
When I implement the above, I get an autoform error saying that an argument to doc must be passed when dealing with multiple schema.
How exactly do I do this?
THe documentation specifically states :
Now both schemas are attached. When you insert a document where type:
'simple' in the document, it will validate against only the
SimpleProductSchema. When you insert a document where type: 'variant'
in the document, it will validate against only the
VariantProductSchema.
I Don't know how I need to pass doc = ???? in the template. Could someone guide me?
This is my autoform template:
Form1:
{{#autoForm collection = "pgTemplates" type ="insert" doc= ???? id ="InsertForm1" }}
{{#each afFieldNames}}
{{> afQuickField name=this.name options = afOptionsFromSchema }}
{{/each}}
Form2:
{{#autoForm collection = "pgTemplates" type ="insert" doc= ???? id ="InsertForm1" }}
{{#each afFieldNames}}
{{> afQuickField name=this.name options = afOptionsFromSchema }}
{{/each}}

According to the documentation for autoform:
doc: Required for an update form, and must have at least an _id
property. Pass the current document object, retrieved with a call to
findOne() for example. For an insert form, you can also use this
attribute to pass an object that has default form values set (the same
effect as setting a value attribute on each field within the form).
There is also another parameter schema that may be of use in this case:
schema: Required if collection is not set. This schema will be used to
generate and validate the form prior to submission, so you can specify
this along with a collection if you want to use a schema that is
slightly different from the one your collection uses. However, the
final object will still have to pass validation against the collection
schema. Set to one of the following:
The name of a helper function (no quotation marks) that returns an instance of SimpleSchema.
The name (in quotation marks) of a SimpleSchema instance that is in the window namespace.
So you can try setting the schema parameter according to your specific schema in each case, and also try to pass the current document object in doc.
I suppose the template would look like:
Form1:
{{#autoForm collection = "pgTemplates" schema="schema1" type ="insert" doc=docObject id ="InsertForm1" }}
{{#each afFieldNames}}
{{> afQuickField name=this.name options = afOptionsFromSchema1 }}
{{/each}}
Form2:
{{#autoForm collection = "pgTemplates" schema="schema2" type ="insert" doc=docObject id ="InsertForm1" }}
{{#each afFieldNames}}
{{> afQuickField name=this.name options = afOptionsFromSchema2 }}
{{/each}}
In the above case, you will need to make sure that your schema instances are available properly in the window namespace
Or you can have a helper function returning the specific instance, like:
With helper:
{{#autoForm collection = "pgTemplates" schema=getSchema1 type ="insert" doc=docObject id ="InsertForm1" }}
{{#each afFieldNames}}
{{> afQuickField name=this.name options = afOptionsFromSchema2 }}
{{/each}}

Related

Where can I store a JSON document so that it can be accessed from a template helper multiple times?

In my code, I am trying to access a collection that stores information about books. I'm looping over an array that only stores the ID of each book. Then I am using that ID to query the book from a collection called Books, which stores complete information for each book
Template.myBorrows.helpers({
storeInSession:function(ilendbooksId) {
console.log("storeInSession is called");
var currentBorrowBook = Books.findOne({_id: ilendbooksId});
Session.setAuth('currentBorrowBook' , currentBorrowBook);
},
getAuthor: function() {
var currentBorrowBook = Session.get('currentBorrowBook');
return currentBorrowBook.ItemAttributes[0].Author[0];
},
});
I am querying the book document by the book's _id in the Books collection. Then I am storing it in a session, then calling appropriate methods to get information. The only problem is that I have to do this for an array of books, so every time the previous document in the Session gets overwritten and all my data on my page changes to the most current Session document. How and where can I store each book's document and ensure that the correct information is displayed without it updating to the most current Session doc?
To answer your comment then, you have an array of document _ids and you want to fetch the document in your templates.
html:
<template name="myTemplate">
{{#each array}}
{{#with doc}}
Author: {{author}}
{{/with}}
{{/each}}
</template>
js:
Template.myTemplate.helpers({
array(){ return theArrayOfIdsThatYouveDefined; },
doc(){ return Books.findOne(this); }
});
Inside the {{#each array}} loop this will be an element of the array. The doc helper simply looks up a book from the Books collection and returns it. Now inside the {{#with doc}} block the data context will be a book object.
No session variables or method calls required.

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.

Boolean in nested schema causing required state

I have schemas set up so that I can have an array of complex input sets via autoform. Something like:
address = {
street:{
type: String
},
city: {
type: String
},
active_address: {
type: Boolean,
optional: true
},
...
}
people: {
name:{
type: String
},
address:{
type: [address],
optional: true,
defaultValue: []
}
}
This way adding an address is optional, but if you add an address all of the address fields are required.
Trying to submit the form throws a required error for every field under "address" except for the Boolean, even though the checkbox is not checked.
For reference, I'm creating the form as such:
{{#autoForm collection="people" id=formId type="insert" doc=getDocument autosave=true template="autoupdate"}}
{{> afQuickField name='name' template="autoupdate" placeholder="schemaLabel"}}
{{> afQuickField name='address' template="autoupdate"}}
...
{{/autoForm}}
I'm using custom form templates very heavily based on bootstrap3 form templates that come with autoform.
Tried
Tried adding a hook like so:
formToDoc:function(doc, ss, formId){
for (var i = 0, l = doc.address.length; i < l; ++i){
if (!doc.address[i].active_address){
delete doc.address[i].active_address;
};
}
return doc;
}
Which solves the submit problem, but still inserts an array full of empty strings "" for the other values. This causes the update form to go haywire, similar as to what's illustrated in my other question.
The issue is that the array isn't empty, but instead has an object of empty values. I could probably run over every value in the form and remove all the fields but that feels very hacky and expensive.
I was incorrect in my last assessment. I had removed the defaultValue: [] from the address field in the person schema. Using that with the following code in the formToDoc hook fixes the issue:
for (var i = 0, l = doc.address.length; i < l; ++i){
if (!doc.address[i].active_address){
doc.address[i].active_address = null;
}
}
return doc;

Meteor AutoForm - Invalid Field Name with Array Index

I've got this in my Simple Schema:
"servicesSelected.0.sku" : {
type: String,
optional: true
},
Basically, I want the sku key in the first array item of servicesSelected to be a String and optional.
Here's my form code, which is for a checkbox.
{{> afFieldInput class="track-order-change" type="checkbox" checkbox="true" template="" name="servicesSelected.0.sku" value="hdrPhotos"}}
The error I get is Invalid Field Name "servicesSelected.0.sku"
As soon as I remove the array index in both the schema and the afFieldInput the error goes away, but the point is to validate the data that is in array index 0...
I am going to assume that it's invalid because in JS you can't have a number as the first character in a key name if you are using dot notation.
But Simple Schema and Autoform do not support square bracket notation...
I'm not sure if SimpleSchema allows you to validate an array like this. A custom validation might be necessary.
I understand that the idea here is that the first element of the array can have the sku property, but others cannot. In this case, try the following method:
servicesSelected: {
type: [selectedServiceSchema],
custom: function() {
for(var i=1; i<this.value.length; ++i) {
if(this.value[i].sku) return "SKU set in the wrong service";
}
},
},

Meteor Merge two cursors data of same collection

I have a strange problem here.
I want to merger two cursors data into single cursor of same collection.
Here is my code
{{#each friendsPolls.data}}
{{#if username}}
{{#each questions}}
{{question}}
{{/each}}
{{/if}}
{{/each}}
app.js
Questions:function(){
Meteor.call('isFbExists', this.username, function (error, result) {
if(result) {
var ee=Ques_Coll.find({owner:result._id});
}
})
}
How can I return the cursor to my template, where it substitutes the {{question}} value.
This function is called many times(length fb friends). Each time when this calls server method it checks whether the user exists in my database or not.
If he already exists then I search for his documents and want to display them
However, if I do like above the data is override and it returns the last user results only.
So,each time it search in collection I want to append that cursor to existing one

Resources