Apply certain autovalue keys to all SimpleSchemas - meteor

I have certain keys such as createdAt and updatedAt that should be defined in all schemas. Is there a way to avoid code duplication?
I use the SimpleSchema package.
I need the following code in all of my Schemas.xxx
createdAt: {
type: Date,
optional: true,
autoValue: function() {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset();
}
},
autoform: {
type: 'hidden'
}
},
updatedAt: {
type: Date,
optional: true,
autoValue: function() {
if (this.isUpdate) {
return new Date();
}
},
autoform: {
type: 'hidden'
}
}

Create a sub schema & then include it in every collection, notice the SimpleSchema constructor is now taking an array.
Schema._Basic = new SimpleSchema({
userId: {
type: String,
optional: true
},
createdAt: {
type: Date,
label: 'Created at'
},
updatedAt: {
type: Date,
label: 'Updated at',
optional: true
},
}
});
Schema.Client = new SimpleSchema([Schema._Basic,
{
address: {
type: String
optional: true
}
}
]);

I would do that with help of this very nice package: matb33:collection-hooks This will add before and after hooks to your collections. So you can add createdAt and updatedAt fields like this:
For CollectionName.insert();
CollectionName.before.insert(function (userId, doc) {
var currentDate = new Date();
doc.createdAt = currentDate;
doc.updatedAt = currentDate; // could be also null if you want
});
So that in above exmaple is triggered always just before the insert takes effect. And this is for CollectionName.update();
CollectionName.before.update(function (userId, doc) {
doc.updatedAt = new Date();
});
This is triggered whenever you update your collection.

Related

Meteor User Accounts - OnSignin

I've changed my schema to include sub-schemas. I want to group relevant data together and make it easier to manage. Unfortanly this has broken my registration process. How do I make the autoform insert firstName into the sub-schema. Any thoughts?
Path: at_config.js
AccountsTemplates.addFields([
{
_id: "details.firstName",
type: 'text',
displayName: "First name",
required: true,
minLength: 1,
maxLength: 37
}
]);
Path: Schema.js
AccountsTemplates.configure({
Schema.UserDetails = new SimpleSchema({
firstName: {
type: String,
optional: false
}
});
Schema.UserProfile = new SimpleSchema({
details: {
type: Schema.UserDetails,
optional: true
},
});
Schema.User = new SimpleSchema({
profile: {
type: Schema.UserProfile,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Path: startup.js
Accounts.onCreateUser(function (options, user) {
if (options.profile && options.profile.roles) {
//include the user profile
Roles.setRolesOnUserObj(user, options.profile.roles);
}
if (options.profile) {
// include the user profile
user.profile = options.profile;
}
return user;
});

Combining simple schema errors

I'm trying to combine fields using simple schema. It works for Schema.UserProfile however it doesn't work for Schema.accountStatus.
If I try and populate the field when I create a new account it errors. Any thoughts on why, would really help, thanks?
Path: schemas.js
Schema = {};
Schema.accountStatus = new SimpleSchema({
isUserAccountActive: {
type: Boolean,
optional: true
},
startDate: {
type: Date,
optional: true
},
endDate: {
type: Date,
optional: true
}
});
Schema.UserProfile = new SimpleSchema({
firstName: {
type: String,
optional: false
},
lastName: {
type: String,
optional: true
},
});
Schema.User = new SimpleSchema({
profile: {
type: Schema.UserProfile,
optional: true
},
// Make sure this services field is in your schema if you're using any of the accounts packages
services: {
type: Object,
optional: true,
blackbox: true
},
accountStatus: {
type: Schema.accountStatus,
optional: true
},
// In order to avoid an 'Exception in setInterval callback' from Meteor
heartbeat: {
type: Date,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Path: startup.js
Meteor.startup(function () {
console.log('Running server startup code...');
Accounts.onCreateUser(function (options, user) {
if (options.profile && options.profile.roles) {
//include the user profile
Roles.setRolesOnUserObj(user, options.profile.roles);
}
if (options.profile) {
// include the user profile
user.profile = options.profile;
}
// other user object changes...
// ...
user.isUserAccountActive = false;
return user;
});
});
I see now: isUserAccountActive is a sub-key of accountStatus. Change:
user.isUserAccountActive = false;
to
user.accountStatus = { isUserAccountActive: false };
Not clear why that should yield a server error though, perhaps it's because you're doing this update on the server side.

Accessing nested array in autoform hook

I have a collection that looks like this:
"request":{
type: [Object],
optional: true,
autoValue: function() {
var input = this.field('requestInput');
var type = this.field('requestTypeInput');
var emailTo = this.field('emailToInput');
var direction = this.field('directionInput');
var d = new Date;
//var requestFiles = this.field('requestFiles');
//console.log(requestFiles.value);
if(!!input.value){
if(this.isInsert){
return [{
"_id":Random.id(),
date: new Date(),
type: type.value,
details: input.value,
emailTo: emailTo.value,
direction : direction.value,
// requestFiles: requestFiles.value,
createdBy: this.userId
}];
} else {
return {
$push: {
"_id":Random.id(),
date: new Date(),
type: type.value,
details: input.value,
emailTo: emailTo.value,
direction : direction.value,
// requestFiles: requestFiles.value,
createdBy: this.userId
}
};
}
} else {
this.unset();
}
}
},
'request.$.date': {
type: Date,
optional: true
},
'request.$.details': {
type: String,
optional: true
},
'request.$.createdBy':{
type: String,
optional: true
},
"request.$.type":{
type: String
},
"request.$._id":{
type: String
},
"request.$.emailTo":{
type: String,
max: 1000,
optional: true
},
"request.$.direction":{
type: String,
max: 1000,
optional: true
},
"request.$.requestFiles":{
type: [String],
optional: true
}
What i want to do is use a before hook to set the value of the requestFiles but i cannot access it. This is what I have so far:
before:{
"method-update": function(doc) {
doc.$set.request.requestFiles = arrayOfFiles.list();
return doc;
}
}
this is telling me :
Uncaught TypeError: Cannot set property 'requestFiles' of undefined.
I have also tried:
doc.$set.request.0.requestFiles = arrayOfFiles.list();
doc.$set.request[0].requestFiles = arrayOfFiles.list();
I just want to pass that array value. If there is another solution to passing that value i will accept it.

Cannot insert relationship ID into Aldeed's Autoform MeteorJS framework

New to MeteorJS. I started making a novel Clan/Samurai app to see if I could understand how mongo/meteor and Autoforms handle relationships. I'm trying to make clans and samurai relate to each other so that each Samurai has a specific clan.
I'm attempting to insert the clan data into the Samurai identity. I seem to not be able to.
I've read the following and still seem generally confused on how to implement this. I've tried before, onsuccess, onsubmit hooks. I've attempted to set the schema up so that it works. I mostly get AutoForm undefined or Schema undefined...tons of errors it seems. I've read that it should be client.
I can console log and get it to render but I can't add the new items to the collection.
Random Github made for viewing pleasure
https://github.com/qtheninja/SamuraiAttack
https://github.com/aldeed/meteor-collection2/issues/31
How to add a relationship or reference with AutoForm in Meteor?
Meteor Autoform package with collection2 does not submit the form
//lib/collections/clans.js
Clans = new Mongo.Collection('clans');
Clans.attachSchema(new SimpleSchema({
name: {
type: String,
label: "Clan Name",
max: 100
}
}));
if (Meteor.isServer) {
Clans.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}
//lib/collections/samurais.js
Samurais = new Mongo.Collection('samurais');
Samurais.attachSchema(new SimpleSchema({
title: {
type: String,
label: "Title",
max: 100
},
description: {
type: String,
label: "Description",
optional: true
},
clan: {
type: Clans
}
}));
if (Meteor.isServer) {
Samurais.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}
//client/template/clans/createClan.html
<template name="CreateClan">
<h1>Create New Clan</h1>
{{> quickForm
collection="Clans"
id="insertClanForm"
type="insert"
buttonContent="Create"
}}
<div>
{{> ListClans }}
</div>
</template>
//client/main.js
AutoForm.addHooks('insertSamuraiForm', {
before: {
insert: function(doc, template) {
//modify the document here
doc.clanid= 45;
doc.dance ="start again";
console.log("running after hook");
return true;
}
}
});
AutoForm.hooks({
insertSamuraiForm: {
before: {
insert: function(doc, template) {
//modify the document here
doc.projectid= "random";
doc.dance ="start again";
console.log('this is asecond form');
}
}
}
});
I was able to resolve this issue by doing the following.
Return on object using 'before' hook
Router.current().params._id
a. I was using iron router and in my url was clans/_id/samurai/new
added 'dance' and 'clanid' as apart of the simpleschema. I had neglected to include them as apart of the schema so I was getting the console.log to work but not the data to be apart of the object.
//client/lib/main.js (alterations)
before: {
insert: function(doc, template) {
//modify the document here
doc.clanid= Router.current().params._id;
doc.dance ="start again";
console.log("running after hook");
return doc;
}
}
//lib/collections/samurais.js
Samurais = new Mongo.Collection('samurais');
Samurais.attachSchema(new SimpleSchema({
title: {
type: String,
label: "Title",
max: 100
},
description: {
type: String,
label: "Description",
optional: true
},
clanid: {
type: String,
label: "ignore this",
optional: true
},
dance: {
type: String,
optional: true
}
}));
if (Meteor.isServer) {
Samurais.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc, fieldNames, modifier) {
return true;
},
remove: function (userId, doc) {
return true;
}
});
}

Error when updating an object in auto-form with meteor

I have checked the docs but I cannot get my head around this. I have an object that I want to update using Auto-Form and Collections2 with meteor.
//Schema
Records = new Mongo.Collection('records');
var Schemas = {};
Schemas.Record = new SimpleSchema({
title: {
type: String,
label: "Title",
max: 200
},
caption: {
type: String,
label: "Caption",
max: 200
},
text: {
type: String,
label: "Detailed text",
optional: true,
max: 1000
},
loc: {
type: Object,
optional: true,
blackbox: true
},
createdAt: {
type: Date,
autoform: {
type: "hidden"
},
autoValue: function() {
if (this.isInsert) {
return new Date;
}
else if (this.isUpsert) {
return {
$setOnInsert: new Date
};
}
else {
this.unset();
}
}
},
updatedBy: {
type: String,
autoValue: function() {
return Meteor.userId();
}
}
});
Records.attachSchema(Schemas.Record);
I have a hook so that I assign the object before update
AutoForm.hooks({
insertCommentForm: {
before: {
insert: function(doc) {
doc.commentOn = Template.parentData()._id;
return doc;
}
}
},
updateRecordForm: {
before: {
update: function(doc) {
console.log("storing location data");
doc.loc = Session.get('geoData');
console.log(doc.loc);
return doc;
}
}
}
});
I get this error.
Uncaught Error: When the modifier option is true, all validation
object keys must be operators. Did you forget $set?
I don't know how to "$set" with autoform.
when you are trying to update a document in Mongo, when you want to update only certain fields, you will use the $set modifier.
Records.update({ _id: 1 }, { $set: { loc: { lat: 12, lng: 75 } } })
The above would update only the loc value.
Records.update({ _id: 1 }, { loc: { lat: 12, lng: 75 } })
The above would remove all other keys and the record will only have the _id and the loc.
Your hook will have to set the loc key in doc.$set.
Please update your hook with the following code and it should work:
updateRecordForm: {
before: {
update: function(doc) {
console.log("storing location data", doc);
doc.$set.loc = Session.get('geoData');
return doc;
}
}
}

Resources