Can any one tell me why this work in meteor:
"landTenancyType" : {
type: String,
optional: true,
autoform: {
type: "selectize",
options: function(){
return [
{label: "Joint", value: "Joint"},
{label: "Tenancy In Common", value: "Tenancy In Common"}
]
}
}
}
but this does not work:
"landTenancyType" : {
type: String,
optional: true,
autoform: {
type: "selectize",
options: function(){
return Categories.find().map(function(obj) {
console.log(obj);
return { label: obj.name, value: obj.name };
});
}
}
}
All the necessary publish and subscribe are working. Console does also show that values are coming from the collection. However a blank selectize ui is killing me. If i change type: "selectize", to type: "select", the select list is populated but i do not have the selectize goodness i need. Any ideas what I am doing wrong?
By the way I am using meteor with autoform 5.0 and comerc:autoform-selectize.
I think the problem is in this line:
Categories.find().map(function(obj)
find returns a cursor, you could do find().fetch() to get an array. Then map would work on that array.
Can you return object wittin another objects from a function ? A function will always return a single entity (either single value or single object). Please re-check your code's following section:
options: function(){
return Categories.find().map(function(obj) {
console.log(obj);
return { label: obj.name, value: obj.name };
});
}
Related
I'm trying to insert an array into an object and I'm not having any luck. I think the schema is rejecting it based on validation but I'm not sure why. If I console.log(this.state.typeOfWork) and check typeof it states its an Object which contains:
(2) ["Audit - internal", "Audit - external"]
0: "Audit - internal"
1: "Audit - external"
My collection after an update contains:
"roleAndSkills": {
"typeOfWork": []
}
Example: Schema
roleAndSkills: { type: Object, optional: true },
'roleAndSkills.typeOfWork': { type: Array, optional: true },
'roleAndSkills.typeOfWork.$': { type: String, optional: true }
Example: update
ProfileCandidate.update(this.state.profileCandidateCollectionId, {
$set: {
roleAndSkills: {
typeOfWork: [this.state.typeOfWork]
}
}
});
Simple schema has some problems with validation on Objects or Arrays, i had the same problem in a recent app i developed.
What can you do?
well, what i did, on the Collections.js file, when you are saying:
typeOfWork:{
type: Array
}
Try adding the property blackbox:true, like this:
typeOfWork:{
blackbox: true,
type: Array
}
This will tell your Schema that this field is taking an Array, but ignore further validation.
The validation i made was on main.js, just to be sure i had no empty array and the data was plain text.
As requested here is my update method, im my case i used objects not arrays but it works the same way.
editUser: function (editedUserVars, uid) {
console.log(uid);
return Utilizadores.update(
{_id: uid},
{$set:{
username: editedUserVars.username,
usernim: editedUserVars.usernim,
userrank: {short: editedUserVars.userrank.short,
long: editedUserVars.userrank.long},
userspec: {short: editedUserVars.userspec.short,
long: editedUserVars.userspec.long},
usertype: editedUserVars.usertype}},
{upsert: true})
},
here it the collection schema
UtilizadoresSchema = new SimpleSchema({
username:{
type: String
},
usernim:{
type: String
},
userrank:{
blackbox: true,
type: Object
},
userspec:{
blackbox: true,
type: Object
},
usertype:{
type: String
}
});
Utilizadores.attachSchema(UtilizadoresSchema);
Hope it helps
Rob
typeOfWork is an Array. You should push your value in it :
$push: {
"roleAndSkills.typeOfWork": this.state.typeOfWork
}
for multiple values :
$push: {
"roleAndSkills.typeOfWork": { $each: [ "val1", "val2" ] }
}
mongo $push operator
mongo dot notation
You state that this.state.typeOfWork is an array (of strings) but then when you .update() your document you are enclosing it in square brackets:
ProfileCandidate.update(this.state.profileCandidateCollectionId, {
$set: {
roleAndSkills: {
typeOfWork: [this.state.typeOfWork]
}
}
});
Simply remove the redundant square brackets:
ProfileCandidate.update(this.state.profileCandidateCollectionId, {
$set: {
roleAndSkills: {
typeOfWork: this.state.typeOfWork
}
}
});
Also since your array is just an array of strings you can simplify your schema a bit by declaring it as such with [String] for the type:
'roleAndSkills.typeOfWork': { type: [String] }
Note furthermore that objects and arrays are by default optional so you can even omit the optional flag.
I am trying to build a kind of specific simple schema for a collection and i would like to make sure that :
when the user enter a new select in my selectsCollection, he will put one of the options value as selected value.
For example:
SelectsCollection.insert({name:"SelectOne",deviceType:"Select",options:["option1","option2","option3"],value:"option4",description:"This is the first select"});
this do not have to work. I want him to write only one of the 3 options.
Here my schema :
SelectsCollection = new Mongo.Collection('Selects'); //Create a table
SelectsSchema = new SimpleSchema({
name:{
type: String,
label:"Name",
unique:true
},
deviceType:{
type: String,
allowedValues: ['Select'],
label:"Type of Device"
},
options:{
type: [String],
minCount:2,
maxcount:5,
label:"Select Values"
},
value:{
type: String,
//allowedValues:[options] a kind of syntax
// or allowedValues:function(){ // some instructions to retrieve the array of string of the option field ?}
label:"Selected Value"
},
description:{
type: String,
label:"Description"
},
createdAt:{
type: Date,
label:"Created At",
autoValue: function(){
return new Date()
}
}
});
SelectsCollection.attachSchema(SelectsSchema);
Any Idea ? :)
Thanks a lot !
This could be done with custom validation function of a field, inside this function you could retrieve values from other fields:
SelectsSchema = new SimpleSchema({
// ...
options: {
type: [String],
minCount: 2,
maxcount: 5,
label: "Select Values"
},
value: {
label: "Selected Value",
type: String,
optional: true,
custom() {
const options = this.field('options').value
const value = this.value
if (!value) {
return 'required'
}
if (options.indexOf(value) === -1) {
return 'notAllowed'
}
}
},
// ...
});
Look here custom-field-validation for more information
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
Using SimpleSchema in Meteor with the AutoForm + Select2 plugins , i am trying to generate the Options for a Select field from the database.
The 'occupation' collection is published, and a collection 'Occupation' is defined in Meteor.
In SimpleSchema I have this:-
occupations: {
type: [String],
optional:true,
label: 'Occupation',
autoform:{
type:"select2",
placeholder: 'Comma spaced list of occupations',
options: function () {
Meteor.subscribe('occupations');
return Occupations.find({});
}
}
},
But it does not return the collection results, and crashes the application without an error message.
It seems the best way to handle this is to supply the options list through a helper.
{{> afQuickField name='occupations' multiple=true tags=true options=listOccupations}}
Where listOccupations is a helper within the template containing the form.
Template.myForm.helpers({
listOccupations: function () {
Meteor.subscribe('occupations');
return Occupations.find({}).fetch();
}
});
And we remove the options object from the schena
occupations: {
type: [String],
optional:true,
label: 'Occupation',
autoform:{
type:"select2",
placeholder: 'Comma spaced list of occupations',
}
},
Have you tried, this approach:
autoform: {
options: {
var occupations = [];
Occupations.find().map(function(occ) {
occupations.push(
{label: occ.description, value: occ._id}
);
});
return occupations;
}
}
hope this helps..
I had the same issue. I'm defining my collections schema in /lib/collections folder, and that is running on both server and client side. Given that, the console.log that I had was printing the correct values on server side and an empty array on client side.
What I did was:
if (Meteor.isClient){
Meteor.subscribe('service-categories-list', {
onReady: function(){
const serviceCategories = ServiceCategories.find({}).map(function(item, index) {
return {
label: item.name,
value: item.slug
};
});
Schema2._schema.type.autoform.options = serviceCategories;
}
})
}
I know that using the _schema is not a good idea, but I accept suggestions :)
In my Meteor app, I have a simple array field called relatedSentences. It is defined using SimpleSchema
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
defaultValue: []
},
It's data can be seen in the Mongo console:
"_id" : "ei96FFfFdmhPXxRWb",
"sentence" : "the newest one",
"relatedSentences" : [
"Ls6EyBkbcotcyfLyw",
"6HKQroCjZhG9YCuBt"
],
"createdAt" : ISODate("2015-10-25T11:21:25.338Z"),
"updatedAt" : ISODate("2015-10-25T11:41:39.691Z")
But when I try to access this field using this, it is returned as a raw string.
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this.relatedSentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});
In the console I get an error. See the return value from the this.relatedSentences. It is the contents of the array as a string, with a comma interpolated.
related: Ls6EyBkbcotcyfLyw,6HKQroCjZhG9YCuBt
selector.js:595 Uncaught Error: $in needs an array
Not sure what is going on here.
Some Progress
I have made some progress, but not yet at a solution. By adding blackbox: true to the SimpleSchema definition, what looks like an array is now returned... but alas it is still failing. See below.
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
blackbox: true,
defaultValue: []
},
Now I get the results below in the console. The values are now being returned as a quoted array, which is what I expected. But the $in is still not seeing it as an array.
["Ls6EyBkbcotcyfLyw", "6HKQroCjZhG9YCuBt"]
selector.js:595 Uncaught Error: $in needs an array
How did the data get populated
In answer to #Kyll - this is how the data was originally populated. I am using AutoForm,
{{> afQuickField name='relatedSentences.0' value=this._id type="hidden"}}
but then adding the array data via a hook.
AutoForm.addHooks('translateForm', {
onSuccess: function (operation, result, template) {
Meteor.subscribe('sentences', function() {
var translatedSentence = Sentences.findOne(result);
var originalSentenceId = translatedSentence.relatedSentences[0]
Sentences.update(
{ _id: originalSentenceId},
{ $push: { relatedSentences: result}
});
Router.go('showSentence',{ _id: originalSentenceId } );
});
}
});
The problem here is the scope of this. You are referring to it inside the subscribe function, where this has a different context. Set a varibale to this in the context where it works, then use that variable instead:
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
var this_related_sentences = this.relatedSentences;
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this_related_sentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});