How to manupulate {{#each something}} in the view ,where "something" is comming from database - meteor

Actually I am new to meteor . I want to manupulate {{#each something}} in my view, without manipulating database. Is there something like i treat it like an array. actually its returning the list of elements.
<select name="field">
<option value="">Lists</option>
{{#each something}}
<option value="{{_id}}">{{name}}</option>
{{/each}}
</select>
JUST I WANT TO SHOW ALL THE ELEMENT within "options" except the LAST element.
Any Help would be appreciated .

if you want to show everything in "something" except the last thing, you can use #index in Blaze to detect when you're at the end. i'm using the each/in construct because i think it's easier to read.
<select name="field">
<option value="">Lists</option>
{{#each thing in something}}
{{#if showThing #index}}
<option value="{{thing._id}}">{{thing.name}}</option>
{{/if}}
{{/each}}
</select>
for the JS, i'm making assumptions about how you get your data, but the helpers would look something like this:
Template.Foo.helpers({
something() {
return Somethings.find({});
},
showThing(index) {
let somethingsCount = Somethings.find({}).count();
return (index != (somethingsCount - 1));
}
});

Related

How do we populate a dropdown list's element from a variable in a collection in Meteor?

I am actually trying to do 2 things here:
With 2 dropdown lists,
a) the first would populate with the products, while
b) the second would populate with the colors according to the first dropdown selected.
I starts off insert a document into the collection as below:
ProductList.insert ({ product: "apple", color: "\"red\",\"green\""});
ProductList.insert ({ product: "banana", color: "\"yellow\",\"green\""});
And this is what I have so far:
Main.html
<template name="prodlist">
<select id="category-select">
<option disabled="disabled" selected="selected">Please Select</option>
{{#each prodlist}}
<option value="{{this}}">{{this}}</option>
{{/each}}
</select>
</template>
<template name="colorlist">
<select id="category-select">
<option disabled="disabled" selected="selected">Please Select</option>
{{#each colorlist}}
<option value="{{this}}">{{this}}</option>
{{/each}}
</select>
</template>
Main.js
Template.prodlist.helpers({
prodlist: function(){
return ProductList.find().map(function(doc) {
return doc.product
})
}
});
Template.colorlist.helpers({
colorlist: function(){
return ProductList.find().map(function(doc) {
return doc.color.split(",") //<-- edited with MrE's answer
})
The reason I insert color: "\"red\",\"green\"" is trying to simulate when you populate the dropdown as hardcode: return ["red", "green"], but it return as one element with the string "red","green". Is there a better approach? Also I don't know if there are packages exists that handle dropdown. Thanks in advance.
why do you try to code a string into an array instead of using an array? I'm not sure what that gets you.
If you 'really' want to use a string, you need to parse it ( with doc.color.split(",") ) into an array instead of doing [doc.color]

Handlebars how to get sibling value inside an object

ok so iv got an object which looks like this:
Magnetim.photos = {
facebook:{albums: {id:["id1","id2","id3","id4"] , albumName:["n1","n2","n3","n4"]}},
}
inside a handlebars template im doing this line of code:
<select id="albums-selection">
{{#each photos.facebook.albums.albumName}}
<option id="{{photos.facebook.albums.id}}" value="{{this}}">{{this}}</option>
{{/each}}
</select>
this outputs this result:
<option id="id1,id2,id3,id4" value="n1">n1</option>
<option id="id1,id2,id3,id4" value="n2">n2</option>
<option id="id1,id2,id3,id4" value="n4">n3</option>
<option id="id1,id2,id3,id4" value="n4">n4</option>
but what i'm trying to achieve is for every name set the id element to its own id, so it looks like this:
<option id="id1" value="n1">n1</option>
<option id="id2" value="n2">n2</option>
etc..
While you are in the {{#each}} statement handlebars provides you with #index variable to track the current item index. Knowing this, you should be able to get corresponding item from other array.
So first you need to step outside of your {{#each}}, this is done by using ../, which will move you one level up.
My initial aproach was simply to do something like this
{{../albumName.[#index]}}
But for some reason that didn't work out. So I wrote the helper to simply grab item from array by index you pass there:
Handlebars.registerHelper('getAlbumName', function(array, id) {
return array[id];
});
Now your handlebars template will look like this:
<script id="template">
<select id="albums-selection">
{{#each id}}
<option id="{{this}}" value="{{getAlbumName ../albumName #index}}">
{{getAlbumName ../albumName #index}}
</option>
{{/each}}
</select>
</script>
<div id="output"></div>
And here is the js:
var Magnetim = {};
Magnetim.photos = {
facebook: {
albums: {
id: ["id1", "id2", "id3", "id4"],
albumName: ["n1", "n2", "n3", "n4"]
}
}
};
var source = $("#template").html();
var template = Handlebars.compile(source);
Handlebars.registerHelper('getAlbumName', function(albums, id) {
return albums[id];
});
$("#output").html(template(Magnetim.photos.facebook.albums));
Final jsfiddle with everything in place

How do I indicate 'checked' or 'selected' state for input controls in Meteor (with spacebars templates)?

So I'm trying to be efficient and clean in my Spacebars templates as I work with Meteor. But I'm stumped by the way in which checkboxes and select options are to be dealt with. Suppose I want to have a checkbox set as checked or not depending on a flag that is in a document in one of my collections. I don't appear to be able to do the following:
<input type='checkbox' id='item-{{this.item_id}}' {{#if checked}}checked{{/if}} />
When I try this, I get the following error:
A template tag of type BLOCKOPEN is not allowed here.
If I try the following options, though, they all result in the checkbox being checked even when the flag is false:
<input type='checkbox' id='item-{{this.item_id}}' checked='{{#if checked}}true{{/if}}' />
<input type='checkbox' id='item-{{this.item_id}}' checked='{{#if checked}}true{{else}}false{{/if}}' />
I have the same trouble with selected in my select options, so I end up doing something like the following to get around it, which seems verbose and error-prone:
<select id='option-{{this.item_id}}'>
{{#if option_60}}
<option value='60' selected>1 hour</option>
{{else}}
<option value='60'>1 hour</option>
{{/if}}
{{#if option_90}}
<option value='90' selected>90 mins</option>
{{else}}
<option value='90'>90 mins</option>
{{/if}}
{{#if option_120}}
<option value='120' selected>2 hours</option>
{{else}}
<option value='120'>2 hours</option>
{{/if}}
</select>
You can use non-block helpers for placing such arguments:
UI.registerHelper('checkedIf', function(val) {
return val ? 'checked' : '';
});
<input type="checkbox" {{checkedIf checked}}>
Here is an example of the code I use to solve this problem, this should be pretty straightforward.
JS
Template.myTemplate.helpers({
checked:function(){
// assumes that this.checked is the flag in your collection
return this.checked?"checked":"";
},
options:function(){
// store options in a helper to iterate over in the template
// could even use http://momentjs.com/docs/#/durations/humanize/ in this case ?
return [{
value:60,
text:"1 hour"
},{
value:90,
text:"90 mins"
},{
value:120,
text:"2 hours"
}];
},
selected:function(value){
// compare the current option value (this.value) with the parameter
// the parameter is the value from the collection in this case
return this.value==value?"selected":"";
}
});
Template.parent.helpers({
dataContext:function(){
// dummy data, should come from a collection in a real application
return {
checked:true,
value:90
};
}
});
HTML
<template name="myTemplate">
<input type="checkbox" {{checked}}>
<select>
{{#each options}}
{{! ../ syntax is used to access the parent data context which is the collection}}
<option value="{{value}}" {{selected ../value}}>{{text}}</option>
{{/each}}
</select>
</template>
<template name="parent">
{{> myTemplate dataContext}}
</template>
EDIT : using universal helpers as Hubert OG hinted at :
JS
Template.registerHelper("checkedIf",function(value){
return value?"checked":"";
});
Template.registerHelper("selectedIfEquals",function(left,right){
return left==right?"selected":"";
});
HTML
<template name="myTemplate">
<input type="checkbox" {{checkedIf checked}}>
<select>
{{#each options}}
<option value="{{value}}" {{selectedIfEquals value ../value}}>{{text}}</option>
{{/each}}
</select>
</template>
The best, most efficient and effective way to accomplish this is to setup global template helpers, one each for determining checked and selected values. For documentation on creating global template helpers, see this documentation.
For checked, I suggest implementing it in this way:
Template.registerHelper('isChecked', function(someValue) {
return someValue ? 'checked' : '';
});
For selected, I suggest implementing it in this way:
Template.registerHelper('isSelected', function(someValue) {
return someValue ? 'selected' : '';
});
With these two global template helpers implemented, you can use them in any of your templates within your application like this:
<template name="someTemplate">
<input type="checkbox" {{isChecked someValue}}>
<select>
{{#each someOptions}}
<option {{isSelected someValue}}>{{someDisplayValue}}</option>
{{/each}}
</select>
</template>

Preselecting option in Meteor

Trying to implement a popup that allows you to modify an existing database record. As part of this, I have a couple of select boxes that I need to prepopulate with existing selections. This seems harder to do that I first thought. Here's a snippet of what I have as my template
{{#with myExistingRecord}}
<select class="myselect">
{{#each hoursInTheDay}}
{{#if isSelectedHour}}
<option selected>{{this}}</option>
{{else}}
<option>{{this}}</option>
{{/if}}
{{/each}}
</select>
{{/with}}
The problem I run into is in the isSelectedHour template function, because this can't have two definitions (the first being the #each value and the second being the record object). I need to compare the value in the #each loop with the value in my record, and I can't think of an elegant way to do this. I could always set my record value as a Session variable, but that's hacky.
Is there a good, non-hacky way to do this?
I had the same problem, and to my surprise there is a good way to this. You do have access to the outer context in the templating section, and you can use that to pass this to a value to a helper function. I would rewrite your code as follows:
<template name="myTemplate">
{{#with myExistingRecord}}
<select class="myselect">
{{#each hoursInTheDay}}
<option {{selected ../recordHour}}>{{this}}</option>
{{/each}}
</select>
{{/with}}
</template>
And then have a helper function:
Template.myTemplate.selected = function(hour) {
if (hour == currentHour)
{ return "selected ";}
else
{ return "";}
};
Look here for details on how the ../ notation works.
In the end I decided to create a simple Handlebars helper to handle this. If anyone wants to do something similar, here's the helper code:
Handlebars.registerHelper('hourOptions', function(selectedHour) {
var html = '';
for (var hr = 0; hr < 24; hr++) {
if (hr === selectedHour)
html += '<option selected>' + hr + '</option>';
else
html += '<option>' + hr + '</option>';
}
return new Handlebars.SafeString(html);
});
And the template code becomes
{{#with myExistingRecord}}
<select class="myselect">
{{hourOptions mySelectedHour}}
</select>
{{/with}}

Meteor form state not being saved

I'm having problems trying to make a reactive form. When I insert data into one collection, the other select is refreshed also. This happens with input fields also, everything gets cleared when I update one of the bound collections.
Is this supposed to happen?
My test code:
<template name="test">
<form class="form-horizontal well" id="test-form">
<select class="input-xlarge" name="item_id">
{{#each types}}
<option value="{{_id}}">{{name}}</option>
{{/each}}
</select>
<select class="input-xlarge" name="category_id">
{{#each categories}}
<option value="{{_id}}">{{name}}</option>
{{/each}}
</select>
</form>
</template>
And my helpers are:
Template.accounts.type = ->
Types.find({}).fetch()
Template.accounts.categories = ->
Categories.find({}).fetch()
I think this is a limitation of Meteor right now, hopefully it'll be resolved in the future.
As discussed on irc, some ways to get around it:
Separate them into different templates
Wrap them in a helper that calls Meteor.ui.chunk.
Use a session variable to track the currently selected state. For example:
Template.accounts.events = {
'change #category_id': function() {
Session.set('selected_category_id', $(this).val());
}
}
(and code to initially select the value in Session.get('selected_category_id') if not undefined in the template).

Resources