insert new doc via autoform hooks call meteor method - meteor

I want to insert a new document into db using autoform. Autoform hook calls a meteor method on server to insert the document.
I have this in template...
{{#autoForm collection="Reports" id="addReport" type="insert"}}
<div class="row">
<div class="col s6">
{{> afQuickField name='hours'}}
</div>
</div>
<button class="btn waves-effect waves-light modal-action modal-close"><i class="material-icons">save</i></button>
{{/autoForm}}
Then...
AutoForm.hooks({
addReport: {
onSubmit: function(insertDoc) {
Meteor.call('addReport', insertDoc, function(error, result) {
if (error) alert(error.reason);
});
return false;
}
}
});
then the method on server...
Meteor.methods({
addReport: function(insertDoc) {
var report = _.extend(insertDoc, {
userId: Meteor.userId(),
});
return Reports.insert(report);
}
});
I have a createdAt and updatedAt fields in collection, but they all have autoValue thus, I believe no need to do insertion from client or in the meteor method.
So collection with schema looks like this:
Reports = new Meteor.Collection('reports');
Reports.attachSchema(new SimpleSchema({
hours: {
type: Number,
label: "Number of hours",
decimal: true
},
createdAt: {
type: Date,
label: "Created Date",
autoValue: function() {
if (this.isInsert) {
return new Date;
} else {
this.unset();
}
},
denyUpdate: true
},
updatedAt: {
type: Date,
autoValue: function() {
if (this.isUpdate) {
return new Date()
}
},
denyInsert: true,
optional: true
},
"userId": {
type: String,
autoform: {
type: "hidden",
}
},
}));
When i run meteor, form displays, but submit does nothing. No visual cue as to if any error. No error message in both client and server console.
what am I doing wrong or missing?

Since #Cristo GQ got it right, I just want to make sure the answer is clear enough for future visitors of this thread
The onSubmit hook will be used only for autoForms with type='normal' or without any type= at all
On another note, the before.insert hook is just for type='insert' And there is no before.normal hook
This mean that when using the onSubmit hook, we have to do any "before work" (like adding currentUser to the doc) inside the onSubmit itself.

aldeed/meteor-autoform documentation:
// Called when form does not have a `type` attribute
onSubmit: function(insertDoc, updateDoc, currentDoc) {
Meteor.call()...
}
I'm following discovermeteor book, and I'm trying to use some methods of the book, but using the meteor-autoform package.
post_submit.html
<template name="postSubmit">
{{#autoForm collection="Posts" id="insertPost"}} <-- no type
<div class="form-group">
<div class="controls">
{{> afQuickField name='title' class='title form-control'}}
</div>
</div>
<div class="form-group">
<div class="controls">
{{> afQuickField name='description' class='description form-control'}}
</div>
</div>
<input id="send" type="submit" value="Send" class="btn btn-primary"/>
{{/autoForm}}
</template>
post_submit.js
var postSubmitHook = {
onSubmit: function(insertDoc){
Meteor.call('postInsert', insertDoc, function(error, result) {
if (error){
Bert.alert(error.reason, 'danger', 'growl-top-right');
$('#send').removeAttr('disabled');
return;
}
Router.go('postPage', {_id: result._id});
});
return false;
}
};
AutoForm.addHooks('insertPost', postSubmitHook);

Related

Get all current values in a collection when defining its simples chema

So I have a semantic type collection here to define my type. It has a field arrayValue. The functionality is the new semantic type here can be an array of existing semantic types, either predefined or defined by the user. The problem is that all the semantic types are stored in the collection itself. So is it possible to get the values in collection (something like SemanticTypes.findOne().semanticType) when defined the schema? Here's the code:
collection:
SemanticTypes = new Meteor.Collection('semanticTypes');
Schemas.SemanticTypes = new SimpleSchema({
semanticType: {
type: String,
regEx: /^[a-zA-Z_][a-zA-Z0-9_]*$/,
unique: true
},
baseType:{
type: String,
autoform: {
options: [
{label: "int", value: "int"},
{label: "float", value: "float"},
{label: "string", value: "string"},
{label: "bool", value: "bool"},
{label: "array", value: "array"}
]
}
},
arrayValue: {
type: String,
optional: true,
autoform: {
options:
// I want to get all current semantic types in the collection now
}
}
});
SemanticTypes.attachSchema(Schemas.SemanticTypes);
html:
<template name="addSemanticTypeForm">
{{#autoForm collection="SemanticTypes" id="insertSemanticTypeForm" type="insert"}}
<fieldset>
{{> afQuickField name='semanticType'}}
{{> afQuickField name='baseType' }}
{{#if isArraySelected}}
{{> afQuickField name='arrayValue'}}
{{/if}}
</fieldset>
<button type="submit" class="btn btn-primary">Add</button>
{{/autoForm}}
</template>
js:
Template.addSemanticTypeForm.onCreated(function() {
Session.set("isArraySelected", false);
});
Template.addSemanticTypeForm.helpers({
isArraySelected: function() {
return Session.get("isArraySelected");
}
});
Template.addSemanticTypeForm.events({
'change select[name=baseType]': function(evt) {
if ($(evt.currentTarget).val() == "array"){
Session.set("isArraySelected", true);
}
else {
Session.set("isArraySelected", false);
}
}
});
I actually found a way to do it by defining an options variable in the helper to get all values in the collection with collection.find(), and use {{> afQuickField name="arrayType" options=arrayOptions}} in html. Here's my code:
js:
Template.addSemanticTypeForm.onCreated(function() {
Session.set("isArraySelected", false);
});
Template.addSemanticTypeForm.helpers({
isArraySelected: function() {
return Session.get("isArraySelected");
},
arrayOptions: function(){
var options = [];
SemanticTypes.find().forEach(function(type){
options.push({label: type.semanticType, value: type.semanticType});
});
return options;
}
});
Template.addSemanticTypeForm.events({
'change select[name=baseType]': function(evt) {
if ($(evt.currentTarget).val() == "array"){
Session.set("isArraySelected", true);
}
else {
Session.set("isArraySelected", false);
}
}
});
html:
<template name="addSemanticTypeForm">
{{#autoForm collection="SemanticTypes" id="insertSemanticTypeForm" type="insert"}}
<fieldset>
{{> afQuickField name='semanticType'}}
{{> afQuickField name='baseType' }}
{{#if isArraySelected}}
{{> afQuickField name='arrayValue' options=arrayOptions}}
{{/if}}
</fieldset>
<button type="submit" class="btn btn-primary">Add</button>
{{/autoForm}}
</template>

SimpleSchema.clean message in console

I'm getting this console message when displaying a group of update forms together. As far as I can tell I've followed the Autoform example correctly. Can anyone tell me what I'm doing wrong?
SimpleSchema.clean: filtered out value that would have affected key "_id", which is not allowed by the schema
Path: form.html
{{#each student}}
{{#autoForm id=makeUniqueID type="update" collection="StudentHistory" doc=this}}
<div class="panel panel-default edit-profile-margin-pannel">
<div class="panel-body">
{{> afQuickField name='class'}}
</div>
</div>
{{/autoForm}}
{{/each}}
Path: form.js
Template.form.helpers({
student: function() {
return StudentHistory.find({});
},
makeUniqueID: function () {
return "update-each-" + this._id;
}
});
Path: Schema.js
StudentHistory = new Mongo.Collection("studentHistory");
StudentHistory.allow({
insert: function(userId, doc) {
return !!userId;
},
update: function(userId, doc) {
return !!userId;
},
remove: function(userId, doc) {
return !!userId;
}
});
var Schemas = {};
Schemas.StudentHistory = new SimpleSchema({
studentUserId: {
type: String,
autoValue: function() {
return this.userId;
},
autoform: {
type: "hidden"
}
},
class: {
type: String,
optional: false
}
});
StudentHistory.attachSchema(Schemas.StudentHistory);
My error was in the template helper. The message disappears when I add the code below.
Template.form.helpers({
student: function() {
return StudentHistory.find({"studentUserId": Meteor.userId()});
}
});

Limiting each inside of each based on context

Having trouble trying to pass some sort of context into my little test chan-clone.
Problem is I have threads, with replies. Showing just the threads works great, showing threads with replies based upon the threads they come from not so much.
Question is how do I send context on the outer each. Thank you so much for the help!
meteorchan.html
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<body>
<h1>Meteor Chan - Let's do this</h1>
<form class="new-thread">
<input type="text" name="text" placeholder="New Thread" />
<button>Submit</button>
</form>
<br/>
{{#each threads}}
{{> thread}}
{{#each replies}}
{{> reply}}
{{/each}}
{{/each}}
</body>
<template name="thread">
<div class="thread">
<span>Anonymous</span> No. {{iden}}
<br>
{{text}}
</div>
<a class="reply" href="#">Reply</a> : <button class="purge">Purge</button>
<form class="new-reply {{this._id}}" style="display:none;">
<input type="text" name="text" placeholder="Add Reply" />
<input type="text" name="thread" value="{{this._id}}" style="display:none;" />
<button>Add New Reply</button>
</form>
<br>
<br>
</template>
<template name="reply">
<div class="reply">
{{text}}
<br>
{{parentThread}}
</div>
</template>
meteorchan.js
Threads = new Mongo.Collection("threads");
Replies = new Mongo.Collection("replies");
if (Meteor.isClient) {
Meteor.subscribe("threads");
Template.body.helpers({
threads: function () {
return Threads.find({}, {sort: {createdAt: -1}});
},
replies: function () {
return Replies.find({}, {sort: {createdAt: 1}});
}
});
Template.body.events({
"submit .new-thread": function (event) {
event.preventDefault();
var text = event.target.text.value;
var currentId = 0;
if(Threads.findOne({}, {sort: {createdAt: -1}})){
currentId = Threads.findOne({}, {sort: {createdAt: -1}}).iden;
}
Threads.insert({
text: text,
createdAt: new Date(),
iden: currentId + 1
});
event.target.text.value = "";
},
"submit .new-reply": function (event) {
event.preventDefault();
var text = event.target.text.value;
var thread = event.target.thread.value;
Replies.insert({
text: text,
createdAt: new Date(),
parentThread: thread
});
event.target.text.value = "";
}
});
Template.thread.events({
"click .purge": function (){
Threads.remove(this._id);
},
"submit .new-reply": function(event){
event.preventDefault();
},
"click .reply": function(){
$('.'+this._id+'.new-reply').css('display','inherit');
}
});
}
if (Meteor.isServer) {
Meteor.publish("threads", function () {
return Threads.find();
});
Meteor.publish("replies", function () {
return Replies.find();
});
}
You can refer to the context in the template helper using this.
So in your replies helper this refers to the current thread you are iterating over using the each.
You can do the following to only fetch replies for the corresponding thread:
replies: function () {
return Replies.find({
// this refers to the current thread
parentThread: this._id
}, {sort: {createdAt: 1}});
}

Meteor: collection empty after insert

I am new to meteor and got stucked and can't understand what am I doing wrong. Enlighten me please.
Here is the HTML file:
<body>
<h1>Do</h1>
{{#if activeTask}}
{{> currentTask}}
{{else}}
{{> newTask }}
{{/if}}
<div>
</div>
</body>
<template name="newTask">
<form>
<label>What<input type="text" name="what" placeholder="gimme an action"/></label>
<input type="submit" value="Go"/>
</form>
<!--
{{> inputAutocomplete settings=settings id="msg" class="input-xlarge" placeholder="action"}}
-->
</template>
<template name="currentTask">
<form>
<label>What<input type="text" name="what" placeholder="gimme an action"/>{{activeTask.what}}</label>
<div>4h 15m</div>
<input type="submit" value="Stop"/>
</form>
</template>
And here is the JavaScript file:
tasks = new Mongo.Collection('tasks');
if (Meteor.isClient) {
Template.body.helpers({
activeTask: function() {
var task = tasks.findOne(
{
endAt: null
},
{
sort: {
startAt: -1
}
}
);
console.log(task);
return task;
}
});
Template.newTask.events({
'submit' : function(event) {
event.preventDefault();
var now = Date.now();
var what = event.target.what.value;
tasks.insert({ what: what, startAt: now, endAt: null });
}
});
}
It successfully adds a new document into the database and logs this in the helper activeTask. One step later it logs no task at all. It has gone. But why?
If you don't have the package autopublish (https://atmospherejs.com/meteor/autopublish) installed, you need to create a publication (client-side) and subscription (server-side):
if (Meteor.isServer) {
Meteor.publish('tasks', function () {
return tasks.find();
});
}
if (Meteor.isClient) {
Meteor.subscribe('tasks');
}
I've also explained working with collections in a recent blog article.

Autoform users profile page

I try create user profile page with autoform, but autorofm tell me "Error: AutoForm: You must specify a collection when form type is insert."
I have only one way through the methods?
Please help me to solve the problem.
Helper
Template.accountForm.helpers({
userSchema: function () {
return Schema.User;
}
});
Template
<template name="accountForm">
<div class="panel-body">
{{#autoForm schema=userSchema collection=Users id="accountForm" type="insert"}}
<fieldset>
{{> afObjectField name='profile'}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
</div>
</template>
Schema
Schema = {};
Schema.UserProfile = new SimpleSchema({
lastname: {
type: String
}
});
Schema.User = new SimpleSchema({
_id: {
type: String,
regEx: SimpleSchema.RegEx.Id
},
email: {
type: String,
regEx: SimpleSchema.RegEx.Email
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
},
services: {
type: Object,
optional: true,
blackbox: false
}
});
Meteor.users.attachSchema(Schema.User);
You don't need the helper function, just use the Meteor.users object.
{{#autoForm collection='Meteor.users' doc=currentUser type='update' id='accountForm'}}
{{> afQuickField name='profile'}}
<button type='submit' class="btn btn-primary">Save profile</button>
{{/autoForm}}

Resources