How to get dropdown option in schema using autoform? - meteor

I want to get the dropdown options from another collection (i.e MyCollection). In this collection i have all the option values (i.e options). I am using collection2 package i want to get all the options in schema only not using helper.
Define Collection :
MyCollection = new Mongo.Collection('mycollection');
collection structure :
{
options : [A, B, C, D, E, F]
}
collection2 schema :
some-schema = new SimpleSchema({
dropdown : {
type : String,
label : "Select One",
autoform : {
options: /*....*/
}
}
});
html :
{{#autoForm schema='some-schema' id='some-id' type="method" meteormethod="some-method"}}
{{> afQuickField name='dropdown'}}
{{/autoForm}}
Any Suggestion...

You can use a function that will be executed in a reactive computation to dynamically compute the list of available options.
SomeSchema = new SimpleSchema({
[...]
dropdown : {
type : String,
label : "Select One",
autoform : {
options: function(){
var doc = MyCollection.findOne();
var docOptions = doc && doc.options;
return _.map(docOptions, function(value){
return {
label: value,
value: value
};
});
}
}
}
[...]
});
You can actually set options in an AutoForm select using many different ways, see for yourself : https://github.com/aldeed/meteor-autoform#what-are-the-various-ways-i-can-specify-options-for-a-select-radio-group-or-checkbox-group

Related

Meteor: Can filter a collection by _id but I can't filter a collection using other fields

I'm fairly new to meteor and I'm still trying to find my way around with filtering collections. Here is my problem, I have a collection defined as follows;
parent_id: {
label: 'Parent ID',
type: String,
},
ar_session_id: {
label: 'Session ID',
type: String,
},
I have inserted some documents and here is one;
{
"_id" : "oQdtbBtKXHzdxWvzn",
"parent_id" : "dJkbDBXut5WzwkaFN",
"ar_session_id" : "dJkbDBXut5WzwkaFNuz77MFgcuGyvgokip",
"question" : "Do you have blah blah...?",
"answer" : "no",
"createdAt" : 1564563509127
}
I am able to filter using parent_id but I can't filter using ar_session_id
var parent_id = "dJkbDBXut5WzwkaFN";
var ar_session_id = "dJkbDBXut5WzwkaFNuz77MFgcuGyvgokip";
qry1 = AssessmentResponse.find({parent_id: parent_id}).fetch();
qry2 = AssessmentResponse.find({ar_session_id: ar_session_id}).fetch();
qry2 returns an empty set. What is it that I am missing?
The only reason I could think of would be if you are not publishing ar_session_id in the client.
For instance if you had something like this:
Meteor.publish("AssessmentResponse", function () {
return AssessmentResponse.find({}, { fields: { ar_session_id: 0 } });
});
Otherwise there is no reason the filtering would be empty, assuming you don't have any typo.

Meteor array returned as string to this

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;
});
}
});

Autoform: can I specify the options helper in the schema?

Is there any way to specify the options helper in the schema? I tried:
Schema
{
favoriteColor: {
type: String,
autoform: {
options: "colorOptions"
}
}
}
But it does not seem to work.
The following technique works fine to display a select with options in a form:
Schema
{
favoriteColor: {
type: String
}
}
Helper
Template.myFormTemplate.helpers({
colorOptions: function () {
return Colors.find().map(function (c) {
return {label: c.name, value: c._id};
});
}
});
Template
{{> afQuickField name="favoriteColor" options=colorOptions}}
In my actual schema I have an array of objects, and in each object I need to select an item from different collection. When you use afArrayField you can no longer set the options in the template as I did in the Template above (because it's an array of objects, and one element in the object would refer the helper).
Is my only option to query the database when I define the scheme? That I guess would make it non reactive, right?
{
favoriteColor: {
type: String,
autoform: {
options: function () {
return Colors.find().map(function (c) {
return {label: c.name, value: c._id};
});
}
}
}
}
Inserting the helper function directly into the schema will work. I'm doing something similar and it is reactive.

Native 'change' event when using Select2 in Meteor.js?

I am using the select2 package from atmosphere in my Meteor.js-project. I am however unable to get the native 'change' to my event-handler in the template. I need this to access the object context in the template.
This does not fire when changing the select value in a Select2-select box:
Template.myTemplate.events({
'change .newValue' : function () {
console.log("I am not fired :(");
console.log("But I can access this. :)", this);
}
}
This, however, does work. The only problem is that I can't access the "this" context from the template, which is what I need.
Template.myTemplate.rendered({
var self = this.data;
$('.newValue')
.select2()
.on('change', function () {
console.log("I am fired! :)");
console.log("I can access self, and get the currently logged in user", self);
console.log("But that is not what I want. :(");
}
}
Select2 rewrites the <select> tag into a series of <div>s, so you don't actually have a change event for the native event handler to grab.
What you could do is stash the _id property of your template data in the id of your select2 element. Your select2 on change listener passes a jQuery event and using it's target you can recreate the missing context. It's ugly but works.
Edit:
What I mean is put the Mongo document _id into the html element id field, like so:
template.html
//...
{{#each dropdown}}
<select id="{{_id}}" class="select2">
{{#each options}}<option value="{{ serialNo }}">{{ name }}</option>{{/each}}
</select>
{{/each}}
//...
template.js
Template.template.rendered = function () {
$('select2').select2({
// ...
}).on('change', function (e) {
console.log(e.target);
});
// ...
Template.template.dropdown = function () {
return Dropdowns.find();
}
Assuming your dropdown document was something like:
{
"_id" : "7MzpRfzyCDTgz4QXJ",
"name" : "dropdown1",
"options" : [
{
"serialNo" : 1,
"name" : "Option 1"
} , {
"serialNo" : 2,
"name" : "Option 2"
}
]
}

I'm doing model binding using backbone.stickit. How can I bind a prepopulated select with a model?

I have a form with a select populated with options. I want to bind it to a model using backbone.stickit but the documentation show how to populate the select on the binding configuration. I can't found an easy way to bind the model with my prepopulated select.
This is my html
<div id="main">
<form id="formulario">
<input id="test1" type="text" />
<select id="test2">
<option value="0">a</option>
<option value="1">b</option>
</select>
</form>
<div id="value-test1"></div>
<div id="value-test2"></div>
</div>
This is a working example based on the documentation, but not what I need
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
return [
{value: 0, label:'a'},
{value: 1, label:'b'}
];
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/nDjHh/
I tried to obtain the option values from the select on the binding configuration using jquery but doesn't work
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
options = $("#test2 option").map(function(){
return {value: this.value, label: this.text};
}).get();
return options;
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/2EYV7/2
It worked, but I think it will be a mess on forms with many selects
window.options = $("#test2 option").map(function(){
return {value: this.value, label: this.text};
}).get();
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
return window.options;
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/Y3aEF/1
What is the best way to bind a prepopulated select to a model?
I tried only with backbone.stickit, it's easier with another library?
Stickit actually binds values as data to select-options instead of using the value html attribute. The reasoning behind this is that in rich apps, you often want to use different types of data for option values. For example, you may want an option to represent a JavaScript Object or Array which is not an easy value to serialize to an html attribute; or you may want to assign the attribute value to the Number 2, but because of type coercion when it is saved as an attribue it will be converted to the String "2". Also, since Stickit is going to parse/own the select-options, it makes sense to let Stickit render the options instead of rendering/processing it in two places (not to mention iterating in a template is ugly).
That said, this request is common enough that I'm convinced to support pre-rendered select-options. Can you open a new issue, and I'll get something out on master within the next couple of days?
EDIT: This is being actively worked on, now.

Resources