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!
Related
I'm using reactive table package from aslagle in my app and I want to create in-line editing, I searched and I found that there's x-editable package for Meteor, so how can I use aslagle:reactive-table package with workman:x-editable-reactive-template package?
I tried this:
Reactive-Table settings:
tableSettings: function () {
return {
collection: fLogCollection,
rowsPerPage: 10,
showFilter: true,
fields: [
{ key: 'name', label: 'Name'},
{ key: 'amount',
label: 'Amount',
tmpl: Template.xEditableAmount
},
{ key: 'cashFrom', label: 'Cash From'},
{ key: 'dateIs', label: 'Date', sortOrder: 0, sortDirection: 'descending'},
{ key: 'controls', label: 'Controls', fn: function () {
return new Spacebars.SafeString(
"<button class='editFlog'><span class='glyphicon glyphicon-pencil'></span> </button>"+
"<button class='delete'><span class='glyphicon glyphicon-remove'></span> </button>"
); } },
{ key: 'createdAt', label: 'createdAt', hidden: true },
],
};
},
xEditableAmount template:
<template name="xEditableAmount">
{{amount}}
</template>
This code to get the x-editable rendered:
Template.fLog.onRendered(function() {
this.$('.editable').editable({
success: function (response, newValue) {
if(response.status == 'error') return response.msg; //msg will be shown in editable form
else Meteor.call('flog.edit2', this._id, newValue);
},
});
});
I succeeded in making x-editable render but
I failed at getting the field updated with the new value in collection...
You can inject templates into fields which makes it convenient to add almost anything you want.
Template helper:
tableSettings: function() {
return {
collection: foo,
fields: [
{
key: 'foo_1',
label: 'Foo 1',
tmpl: Template.foo1,
},
{
key: 'foo_2',
label: 'Foo 2',
tmpl: Template.foo2,
},
{
key: 'foo_2',
label: 'Foo 2',
tmpl: Template.foo2,
}
]
};
}
In foo2 helper (copied directly from workman/x-editable-reactive-template atmosphere page):
Template.foo2.helpers({
onSuccess: function () {
var id = this._id;
return function (res, val) {
MyColl.update({ _id: id }, { $set: { prop: val } });
}
}
});
In your Templates:
<template name='table>
{{> reactiveTable settings=tableSettings}}`
</template>
<template name='foo1'>
<!-- Any html (below pasted from docs (link at bottom of post)-->
superuser
</template>
<template name='foo2'>
{{> xEditable type="text" success=onSuccess placement="right" }} <!-- put your workman:x-editable-reactive-template here -->
</template>
This should get you pointed in the right direction.
https://vitalets.github.io/x-editable/docs.html
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}}
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
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`.
}
}
}
});
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}}