AutoForm.getFieldValue for array fields - meteor

I have a schema declared as:
JobSchema = new SimpleSchema({
responsibilities: {
type: [String],
optional: true
},
'responsibilities.$': {
min: 2,
autoform: {
afFieldInput: {
class: 'form-control'
},
placeholder: 'E.g. "Build tools according to specifications"'
}
}
});
Also I have an UI helper declared as:
Template.registerHelper('currentFieldValue', function (fieldName) {
return AutoForm.getFieldValue('insertJobForm', fieldName) || '';
});
I have a template where I used this helper to generate a form preview. It works like charm for all fields except the array ones. Nothing is being rendered. Any ideas?
{{# if currentFieldValue "responsibilities"}}
<h3>Responsibilities</h3>
{{{currentFieldValue "responsibilities"}}}
{{/if}}

A quick and dirty workaround:
job_create.js
Template.jobCreate.helpers({
responsibilities: function() {
var formData = AutoForm.getFormValues('insertJobForm');
return formData.insertDoc.responsibilities || [];
}
});
job_create.html
{{# if responsibilities}}
<h3>Responsibilities</h3>
{{responsibilities}}
{{/if}}

Related

Difference between defaultValue and autoValue in Autoform?

I'm working on a project which I start with using autoValue as
Programs.attachSchema(new SimpleSchema({
createdBy: {
type: String,
autoValue: function() {
return this.userId
},
optional: true,
autoform: {
type: 'hidden'
}
},
createdAt: {
type: Date,
label: "Created At",
defaultValue: new Date(),
optional: true,
autoform: {
type: 'hidden'
}
}
}));
everything works find until I need to update the information by other users, let's say admin, Programs.update or Programs.insert methods will change the email field.
I tried to use defaultValue for createdBy field but
defaultValue: this.userId
return me null
and i'm not allowed to use
defaultValue: Meteor.userId()
Can anyone explain the difference? I tried use function() {return this.userId} for defaultValue which still got no luck
defaultValue is used by simple-schema for defining default value. There are some quirks so read the docs: https://github.com/aldeed/meteor-simple-schema#defaultvalue
Think of when the code is ran and you will understand why you can't use Meteor.userId() or this.userId for defaultValue. The schema is ran once at startup.
What allows autoValue to work is that it returns a function. The function is ran during db updates/inserts. Read over the docs to fully understand it: https://github.com/aldeed/meteor-simple-schema#autovalue
Now, if I understand your question properly, you have issues with autoValue when an admin comes along and modifies the document? Causing the createdBy to be set to the admin's id? To solve something like that, you just need to be more specific with your autoValue function.
See if this code helps guide you in the proper direction:
Programs.attachSchema(new SimpleSchema({
createdBy: {
type: String,
autoValue: function() {
if (this.isInsert) {
return this.userId;
} else if (this.isUpsert) {
return { $setOnInsert: this.userId };
}
this.unset(); // Prevent user from supplying their own value
return undefined;
},
optional: true,
autoform: {
type: 'hidden'
}
},
createdAt: {
type: Date,
label: 'Created At',
defaultValue: new Date(),
optional: true,
autoform: {
type: 'hidden'
},
autoValue: function() {
if (this.isInsert) {
return new Date();
} else if (this.isUpsert) {
return { $setOnInsert: new Date() };
}
this.unset(); // Prevent user from supplying their own value
return undefined;
},
}
}));
You should try this snippet,
new SimpleSchema({
// ...
createdBy: {
autoValue() {
return Meteor.userdId();
}
}
// ...
})
Now the explanation, Your problem is more likely related with the this binding, this.userId, was called from SimpleSchema context in this way this does not have any userId() method, you should use the full namespace in this case Meteor.userId();
A very cool explanation on this binding I recommend you to read
This binding

Meteor reactive tables with FS.Collection

I'm struggling to implement reactive tables based on a FS.Collection object. I've tried both aldeed/meteor-tabular and aslagle/reactive-table but both fail because the collection doesn't appear to exist. However, if I subscribe and retrieve fields from the Collection without using a reactive table package then the data displays just fine. What am I missing? It can't be a coincidence that both packages fail to work...
Here's my implementation with the aslagle/reactive-table package...
//template
<template name="documentTable">
{{#if Template.subscriptionsReady}}
{{> reactiveTable settings=settings}}
{{else}}
{{> spinner}}
{{/if}}
{{#if currentUser}}
{{> fileUpload}}
{{/if}}
</template>
//documents js
Template.documents.onCreated( () => {
p_id = FlowRouter.current().params.id;
Template.instance().subscribe('documents', p_id);
});
Template.documents.helpers({
documents: function () {
return Documents.find();
},
settings: function () {
return {
collection: documents,
showFilter: false,
rowsPerPage: 5,
showNavigation: auto,
showRowCount: true,
fields: ['_id','userId','propertyId','uploadedAt']
};
}
});
//collection definition
if (Meteor.isServer) {
var docStore = new FS.Store.S3("documents", {
region: "eu-west-1",
accessKeyId: (Meteor.isServer && !process.env.AWS_ACCESS_KEY_ID ? Meteor.settings.AWSAccessKeyId : null),
secretAccessKey: (Meteor.isServer && !process.env.AWS_SECRET_ACCESS_KEY ? Meteor.settings.AWSSecretAccessKey : null),
bucket: Meteor.isServer && process.env.AWS_S3_BUCKET || Meteor.settings.AWSBucket,
folder: "documents"
});
Documents = new FS.Collection("Documents", {
stores: [docStore],
filter: {
allow: {
contentTypes: ['application/pdf']
}
}
});
}
// end server
if (Meteor.isClient) {
var docStore = new FS.Store.S3("documents");
Documents = new FS.Collection("Documents", {
stores: [docStore],
filter: {
allow: {
contentTypes: ['application/pdf']
}
}
});
}
// end client
// allow rules
Documents.allow({
insert: function(userId) {
// only allow insert from signed in user
return userId != null;
},
update: function(userId) {
// only allow update from signed in uesr
return userId != null;
},
download: function() {
return true;
},
});
In the reactive-table case I'm getting the error that the argument is not an instance of Mongo.Collection, a cursor or an array while with meteor-tabular it fails to start because it encounters a ReferenceError and states that Documents isn't defined.
Anyone any thoughts on this?
I'm using aslagle/reactive-table with mongo quite well, with a pub/sub model; I don't know what your new FS is? is that a mongo collection?
I have something like this when I use the reactive-table...
//on the server
Documents = new Mongo.Collection('documents');
//on the client js
Documents = new Mongo.Collection('documents');
Template.documents.helpers({
settings: function () {
return {
collection: Documents.find(),
rowsPerPage: 5,
showFilter: false,
showNavigation: auto,
showRowCount: true,
fields: [
{key: '_id',
label: 'ID' },
{key: 'userId',
label: 'User#' },
{key: 'propertyId',
label: 'Property#' },
{key: 'uploadedAt',
label: 'Uploaded' },
]
};
}
});
//on the client html file
{{> reactiveTable class="table table-bordered table-hover" settings=settings}}

how to set a default value to element in a collection of type [String]?

i have quickform once the submit button clicked, this method is fired
submitPost: function (app) {
check(app, {
title: String,
description: String,
category: String,
price: Number
});
var knownId = Products.insert(app);
Products.update({ _id: knownId }, { $set:{screenShots: scs, previewImage: pi, sourceCode: zip }});
}
the submit button wasn't working when i didn't give "screenShots, previewImage, and sourceCode" a default values in a collection.
Once i gave them a default value like it is shown below
previewImage: {
type: String,
defaultValue: "jjj",
},
sourceCode: {
type: String,
defaultValue: "jjj",
},
screenShots: {
type: [String],
autoValue: function() {
return [];
}
},
now the submit button in the form is working and the update method is triggered. it updates both "previewImage and sourcCode" but "screenShots" is still empty.
am not sure but i believe the problem has to do with autoValue which i should make it a default value, but how do i give an element that of type array of string a default value?
or the problem has to do with something else?
use optional: true in the schema if the value is optional, and it will pass check if it is empty.
The autoValue option is provided by the SimpleSchema package and is documented there. Collection2 adds the following properties to this for any autoValue function that is called as part of a C2 database operation:
isInsert: True if it's an insert operation
isUpdate: True if it's an update operation
isUpsert: True if it's an upsert operation (either upsert() or upsert: true)
So If you want to provide the autoValue while updating you have to use isUpdate in your schema like this.
createdAt: {
type: Date,
autoValue: function() {
if (this.isInsert) {
return new Date();
} else if (this.isUpsert) {
return {$setOnInsert: new Date()};
} else {
this.unset(); // Prevent user from supplying their own value
}
}
},
So your schema will be something like this:
previewImage: {
type: String,
defaultValue: function() {
if (this.isInsert) {
return 'fff';
} else if (this.isUpdate) {
return 'fff';
}
},
sourceCode: {
type: String,
defaultValue:function() {
if (this.isInsert) {
return 'jjj';
} else if (this.isUpdate) {
return 'jjj';
}
},
screenShots: {
type: [String],
autoValue: function() {
if (this.isInsert) {
return [];
} else if (this.isUpdate) {
return [];
}
}
},
For more info please check this

meteor autoform custom validation message on sibling fields

How do send custom validation message to another schema field ?
SessionSchema = new SimpleSchema({
'seat.from': {
type: String,
max: 10,
optional: false
},
'seat.to': {
type: String,
max: 10,
optional: false
}
});
ReservationSchema = new SimpleSchema({
title: {
type: String
},
sessions: {
type: [SessionSchema],
min: 1,
optional: false,
custom: function() {
//Its an array object. validation is depends on next array so I made a validation here instead of `SessionSchema`.
return "greater-session"; // dispaly error on top of the session. I need to display error message on perticular field in `SessionSchema`.
}
}
});
SimpleSchema.messages({
"greater-session": "From seat should not lesser then previous session"
});
Autoform:
{{#autoForm id="addReservation" type="method" meteormethod="insertMyReservation" collection="Reservation"}}
{{> afQuickField name="title" autofocus=''}}
{{> afQuickField name="sessions" panelClass="group"}}
{{/autoForm}}
How do I achieve this?
I would suggest you using a custom validator for your SimpleSchema. They have access to more context information.
I would try something like this:
ReservationSchema = new SimpleSchema({
title: {
type: String
},
sessions: {
type: [SessionSchema],
min: 1,
optional: false,
custom: function() {
var sessions = this.value; // array;
var seatTo = 0; // initalize # 0
var hasError;
// loop through seach session
_.each(sessions, function(s, index) {
// if seatFrom < previous seatTo
if (s['seat.from'] < seatTo) {
hasError = true;
};
seatTo = s['seat.to']; // update seatTo for next iteration
});
if (hasError) {
return "greater-session"; // dispaly error on top of the session. I need to display error message on perticular field in `SessionSchema`.
}
}
}
});

Meteor collection2 field in $unset list

I have a simpleSchema:
imageUrl: {
type: Object,
optional: true,
autoValue: function() {
if (Meteor.isClient) return;
var imageField = this.field('imageId');
if (!imageField.isSet){
this.unset();
} else {
var imageObj = MealsImages.findOne(imageField.value);
if (imageObj){
return {thumb: imageObj.S3Url('thumb'), big: imageObj.S3Url('big')};
}
}
},
autoform: {
label: false,
type: 'hidden',
afFieldInput: {
type: "hidden"
}
}
},
For some reason, when I update the record this field always appears in $unset array:
Meteor.methods({
mealUpsert: function(doc, mealId) {
check(doc, Meals.simpleSchema());
console.log('test7');
console.log(doc);
if (mealId){
Meals.update({_id: mealId}, doc);
} else {
mealId = Meals.insert(doc);
}
return false;
}
});
Will print:
I20150830-21:49:39.560(-4)? { '$set':
...
I20150830-21:49:39.562(-4)? '$unset':
I20150830-21:49:39.562(-4)? { imageUrl: '',
...
I'm using autoform:
<template name="mealUpdateForm">
<div class="meal-content">
{{> quickForm collection="Meals" doc=this id="mealUpdateForm" meteormethod="mealUpsert" type="method-update"}}
</div>
</template>
And will never be updated or set. Any clue why field could appear in $unset list?
I think I've figured this out - you have a this.unset() in your autoValue for imageUrl. This is called whenever you omit imageId from the modifier, even if it is already present in a document you are modifying!

Resources