Error trying to update document using autoForm with Schema in Meteor - mongodb

Error message:
"Uncaught Error: After filtering out keys not in the schema, your modifier is now empty"
Using autoform with collection2 and simple schema in Meteor.
The schema:
Injuries = new Mongo.Collection('injuries');
Rehab = new SimpleSchema({
exercise: {
type: String,
label: "Rehab Exercise"
},
sets: {
type: Number,
label: "Sets"
},
duration: {
type: Number,
label: "Set Duration (in Minutes)"
},
date: {
type: String,
label: "Date of Rehab Exercise"
},
rehabnotes: {
type: String,
label: "Notes: i.e. 70% Intensity During Sprints",
max: 200
},
injuryid:{
type: String,
}
});
Injuries.attachSchema(new SimpleSchema({
player: {
type: String,
label: "Player",
max: 50
},
injury: {
type: String,
label: "Injury"
},
notes: {
type: String,
label: "Notes",
max: 200
},
injurydate: {
type: Date,
label: "Date of Injury",
},
rehab: {
type: [Rehab],
optional: true
}
}));
And the Form Code in the Template:
{{#autoForm collection="Injuries" schema="Rehab" id="insertRehabForm" type="update"}}
<fieldset>
{{> afQuickField name='exercise' options=options}}
{{> afQuickField name='sets'}}
{{> afQuickField name='duration'}}
{{> afQuickField name='date'}}
{{> afQuickField name='rehabnotes' rows=6}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
I can insert documents just fine with the autoform on the home page, using this custom form on the individual document page I receive the error on submission.
I have one collection hook setup up for before submissions, but this looks like it is just a schema error, perhaps the Rehab array that I have set up on the original Injuries schema is messing this up? The searches I've done for this have all been about the "Type" parameter in the schema not matching what is expected, but I've checked those here and they look good. Suggestions?

Based on the AutoForm's docs: the schema attribute is required if collection attribute is not set, however, even if collection is set AutoForm will still use the provided schema attribute to generate (only applicable to QuickForm) and validate the form (applicable to both AutoForm and QuickForm).
What happened in your case is that since both attributes (schema and collection) are provided, AutoForm first validates the form fields against the Rehab schema and when it succeed, it tries to insert the values of those fields (exercise, sets, duration, date, rehabnotes) to your Injuries collection, which does not have those keys in its own schema (it only has player, injury, notes, injurydate and rehab).
From your requirements, it seems like setting the AutoForm type to update-pushArray is the best possible solution. Check the docs and the example for usage.

Related

Uncaught Error: After filtering out keys not in the schema, your modifier is now empty

everyone. I am working on an attendance system using meteor.js. So I have two collections subject , student. In this system, a form will be submitted with selected studentID and subjectCode for subject enrollment. However, I got this error when I submitted. Uncaught Error: After filtering out keys not in the schema, your modifier is now empty.
The subject schema is like this
const subjectSchema = new SimpleSchema({
subjectCode:{
type: String,
label: “Subject Code”,
index:true,
unique:true
},
subjectName:{
type: String,
label: “Subject Name”,
index:true,
unique:true
},
enrollment:{
type: Array,
optional: true
},
‘enrollment.$’:String,
});
For actions
Template.enroll.events({
'submit form':function(e){
e.preventDefault();
var name = $(e.target).find('[name=studentID]').val();
var subjectCode = $(e.target).find('[name=subjectCode]').val();
subject.update(
{subjectCode:subjectCode},
{$push:{"enrollment.$":name}});
}
});
If anyone could help me out here I would really appreciate it.
Thanks a lot.
The solution is here Meteor Forum.
Code should be like this:
subject.update(
{subjectCode:subjectCode},
{$addToSet:{"enrollment":name}});
}

Cannot access or use documents showing in mongo db terminal

I created a collection called Stampest that stores a reference of an uploaded image and a title string, created by a user. Using the ostrio:autoform package.This package creates a collection called Images where all the user uploaded images are stored and hense referenced to/from.
When I query mongo in my terminal using
db.stampest.find({})
I get the entries
Which shows that there are documents in the database, in the Stampest Collection. But the PROBLEM is that when I look at the collection in Meteor Toys debug, it says its empty, and when I insert a document, in this case, the image and the title, the collection changes to 1 for a split second and geos back to 0. There are no error from the terminal or console
As a consequence, I cannot access these documents, what can I do?
This is the schema.js
Schemas = {};
Stampest = new Meteor.Collection('stampest');
Stampest.allow({
insert: function (userId, doc) {
return userId;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return doc.userId === userId;
},
remove: function (userId, doc) {
// can only remove your own documents
return doc.userId === userId;
}
});
Schemas.Stampest = new SimpleSchema({
title: {
type: String,
max: 60
},
picture: {
type: String,
autoform: {
afFieldInput: {
type: 'fileUpload',
collection: 'Images',
// uploadTemplate: 'uploadField' // <- Optional
// previewTemplate: 'uploadPreview' // <- Optional
}
}
}
});
Stampest.attachSchema(Schemas.Stampest);
The publish is like this:
Meteor.publish('stampest', function () {
return Stampest.find({author: this.userId}).fetch();
console.log(Stampest.find());
});
The user inserts the image and the title like this:
<template name="createStamp">
<div class="grid-block">
<div class="grid-container">
<div class="upload-img">
{{file.original.name}}
</div>
<div class="new-stamp-container">
{{> quickForm collection="Stampest" type="insert" id="insertStampForm" class="new-stamp-form"}}
</div>
</div>
</div>
</template>
From what I see in your code, you are returning an Array of db items and not a Cursor in your code.
If you take a look at https://docs.meteor.com/api/pubsub.html, you'll notice that regular publications return simple cursors or array of cursors but never your fetched data.
edit: also, the console.log in your publication will never be interpreted as it returns on the previous line.

Using objects as options in Autoform

In my Stacks schema i have a dimensions property defined as such:
dimensions: {
type: [String],
autoform: {
options: function() {
return Dimensions.find().map(function(d) {
return { label: d.name, value: d._id };
});
}
}
}
This works really well, and using Mongol I'm able to see that an attempt to insert data through the form worked well (in this case I chose two dimensions to insert)
However what I really what is data that stores the actual dimension object rather than it's key. Something like this:
[
To try to achieve this I changed type:[String] to type:[DimensionSchema] and value: d._id to value: d. The thinking here that I'm telling the form that I am expecting an object and am now returning the object itself.
However when I run this I get the following error in my console.
Meteor does not currently support objects other than ObjectID as ids
Poking around a little bit and changing type:[DimensionSchema] to type: DimensionSchema I see some new errors in the console (presumably they get buried when the type is an array
So it appears that autoform is trying to take the value I want stored in the database and trying to use that as an id. Any thoughts on the best way to do this?.
For reference here is my DimensionSchema
export const DimensionSchema = new SimpleSchema({
name: {
type: String,
label: "Name"
},
value: {
type: Number,
decimal: true,
label: "Value",
min: 0
},
tol: {
type: Number,
decimal: true,
label: "Tolerance"
},
author: {
type: String,
label: "Author",
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden"
}
},
createdAt: {
type: Date,
label: "Created At",
autoValue: function() {
return new Date()
},
autoform: {
type: "hidden"
}
}
})
According to my experience and aldeed himself in this issue, autoform is not very friendly to fields that are arrays of objects.
I would generally advise against embedding this data in such a way. It makes the data more difficult to maintain in case a dimension document is modified in the future.
alternatives
You can use a package like publish-composite to create a reactive-join in a publication, while only embedding the _ids in the stack documents.
You can use something like the PeerDB package to do the de-normalization for you, which will also update nested documents for you. Take into account that it comes with a learning curve.
Manually code the specific forms that cannot be easily created with AutoForm. This gives you maximum control and sometimes it is easier than all of the tinkering.
if you insist on using AutoForm
While it may be possible to create a custom input type (via AutoForm.addInputType()), I would not recommend it. It would require you to create a template and modify the data in its valueOut method and it would not be very easy to generate edit forms.
Since this is a specific use case, I believe that the best approach is to use a slightly modified schema and handle the data in a Meteor method.
Define a schema with an array of strings:
export const StacksSchemaSubset = new SimpleSchema({
desc: {
type: String
},
...
dimensions: {
type: [String],
autoform: {
options: function() {
return Dimensions.find().map(function(d) {
return { label: d.name, value: d._id };
});
}
}
}
});
Then, render a quickForm, specifying a schema and a method:
<template name="StacksForm">
{{> quickForm
schema=reducedSchema
id="createStack"
type="method"
meteormethod="createStack"
omitFields="createdAt"
}}
</template>
And define the appropriate helper to deliver the schema:
Template.StacksForm.helpers({
reducedSchema() {
return StacksSchemaSubset;
}
});
And on the server, define the method and mutate the data before inserting.
Meteor.methods({
createStack(data) {
// validate data
const dims = Dimensions.find({_id: {$in: data.dimensions}}).fetch(); // specify fields if needed
data.dimensions = dims;
Stacks.insert(data);
}
});
The only thing i can advise at this moment (if the values doesnt support object type), is to convert object into string(i.e. serialized string) and set that as the value for "dimensions" key (instead of object) and save that into DB.
And while getting back from db, just unserialize that value (string) into object again.

using both of "collection" and "schema" attribute in autoform

I have one "Ads" collection in mongoDB, and too many schema in following format:
AdsBaseSchema = new SimpleSchema({
_parentId: {
type: String,
optional: true
},
title: {
type: String,
label: "Title",
max: 200
}
description: {
type: String,
label: "Description",
optional: true
}
});
but they are different is some fields.
and I want to use them for insert autoform. like this:
{{> quickForm schema="AdsBaseSchema" id="insBaseAds" type="method" meteormethod="insBaseAds"}}
with this method:
insBaseAds: function(doc) {
Ads.insert(doc);
this.unblock();
}
This approach works correctly! But this is my question:
Its hard for me to use this approach for all of my schema! (as I told because I have too many schema)
I want to ask you:
Is this possible for meteor to use something like below autoform, and use just one autoform (form generator) for all schema?
{{> quickForm collection="Ads" schema="AdsBaseSchema" id="insertAds" type="insert"}}
Is it possible using both of "collection" and "schema" attribute in autoform??
I find a solutio for this issue:
I could try writing a helper for my template which returns a schema name dynamically, like so:
{{> quickForm collection="Ads" schema=schema id="insertAds" type="insert"}}
helper:
Template['myTemplate'].helpers({
schema() {
//Write your logic here
return "adsBaseSchema";
}
})
and fortunately it worked.

Kendo MVVM create new record with remote datasource

I think I'm missing something simple, but I can't find any examples showing how to do this... also, please forgive me if some of the terminology I'm using is wrong.
I simply want to use an HTML form that is bound to a Kendo Observable object to create a new record in my remote datasource.
All the examples I've seen show how to edit existing records, but that's not what I'm looking for (at least not at the moment).
I've created a Fiddle http://jsfiddle.net/matbeard/fYfYz/2/ with a simple cut-down version of what I've got so far. Obviously it won't actually save the record as the create URL doesn't point anywhere, but I'm confident I can handle that.
Can somebody please point me in the right direction? Thanks.
And because I can't post a question without it, here's some code copied from the Fiddle:
var model = kendo.data.Model.define({
id: "id",
fields: {
id: { type: 'number' },
field1: { type: 'string' },
field2: { type: 'string' },
field3: { type: 'string' }
}
});
var viewModel = kendo.observable({
dataSource: new kendo.data.DataSource({
type: 'json',
transport: {
create: {
url: '/myurl/create',
dataType: 'json',
type: 'post'
}
},
schema: {
data: 'data',
model: model
}
});
});
kendo.bind($("#my-form"), viewModel);
Lets do it slightly different...
Your form does not need to (should) be bound to the and object containing the DataSource since you are actually not saving the dataSource but one record.
So, you should define the model as:
var Model = kendo.data.Model.define({
id: "id",
fields: {
id: { type: 'number' },
field1: { type: 'string' },
field2: { type: 'string' },
field3: { type: 'string' }
}
});
The DataSource now becomes an object per-se:
var dataSource = new kendo.data.DataSource({
type: 'json',
transport: {
create: "/myurl"
},
schema: {
model: Model
}
});
And your observable object has data element that is an instance of the Model defined (new Model()).
var viewModel = kendo.observable({
data: new Model(),
mySave: function(e){
console.log("this", this.data);
dataSource.add(this.data);
e.preventDefault();
}
});
So, your form should be now something like:
<form id="my-form">
<input name="field1" data-bind="value:data.field1" type="text" />
<input name="field2" data-bind="value:data.field2" type="text" />
<input name="field3" data-bind="value:data.field3" type="text" />
<button data-bind="click: mySave">Save</button>
</form>
Your JSFiddle modiefied http://jsfiddle.net/6LHx3/4/