Meteor: Spacebars not updating on session-value change - meteor

I have this html-File in Meteor
{{#if thevalue}}
{{> one}}
{{else}}
{{> two}}
{{/if}}
and this helper
'thevalue': Session.get('thevalue') //returns true or false
My problem is that when the Session-Value changes, the if/else-Bracktes from Spacebars do not change with it. I thought Session-Values are reactive...but maybe I have some sort of misconception how this works.

Try to write your helper as a function like so
'thevalue': function () {
return Session.get('thevalue');
}
See the docs here for more.

Session is reactive and helper is a reactive computation. The problem may be the format of your helper which should be like this:
thevalue: function(){
return Session.get('thevalue');
}
The problem could simply be that you are putting 'thevalue' in quotes and turning it in to a string where I believe it needs to run as a function.
Keep in mind if your 'thevalue' is 0 then your spacebars will return {{> two}}.

Related

passing a variable inside helper funtion

I am using a helper inside another helper. I am trying to pass a value ‘post_id’, that i am getting dynamically from ‘show_post’ helper.I want to pass it and then use it inside the query that is returning a set of result back to helper. for some reason , app is crashing. Can someone guide me through this.
{{#each show_post}}
{{posttext}}
{{postedBy}}
{{#each show_comment({{post_id}}) }}
//<--- i am passing the value to helper like this.
<span> <p>{{postedBy}}: <h5>{{commenttext}}</h5>{{createdAt}}</p></span>
{{/each}}
{{/each}}
Template.display_block.helpers({
show_post(){
return PostComment.find({parent: 0},{sort: {createdAt: -1}});
}
});
Template.display_block.helpers({
show_comment(e){
var t1 = e;
var now = PostComment.find({post_id:{$regex:new RegExp(’^’ + t1)}});
return now;
}
});
The first helper generates a array(Mongo Db result).I want to use this array’s elements(that are dynamic) in next helper. So i want to use a variable that can hold the value of array element of first helper and then pass it to next helper. In second helper, i want to pass this variable and use this variable to sort a result in Mongo query. I am new to this so i am unable to understand how this instance
Firstly you don't need to wrap helper arguments in double curly braces or parens.
{{#each show_comment post_id}}
Will do what you need.
You're also making life a bit more complicated for yourself than necessary. You can use the current data context through this in your code. Also unclear why you're using a regex unless you're concatenating something to the post _id.
This allows you to simplify down to:
html:
{{#each show_post}}
{{posttext}}
{{postedBy}}
{{#each show_comment}}
<span><p>{{postedBy}}: <h5>{{commenttext}}</h5>{{createdAt}}</p></span>
{{/each}}
{{/each}}
js:
Template.display_block.helpers({
show_comment(){
return PostComment.find({post_id: this._id);
}
});

Meteor Blaze {{if}} statement to check if array

I have collection that has a document object "wageringStraightSpread" that sometimes is an embedded array. I need to check then look through the array, but i am not sure of the syntax of the {{if}} statement. I am specifically looking for help with this line {{#if team.[0].wageringStats.wageringStraightSpread = array}}. Thank you!
Here's what I got:
{{#if team.[0].wageringStats.wageringStraightSpread = array}}
{{#each}}
{{team.[0].wageringStats.wageringStraightSpread.this.line}}
({{team.[0].wageringStats.wageringStraightSpread.this.money}})
{{/each}}
{{else}}
{{team.[0].wageringStats.wageringStraightSpread.line}}
({{team.[0].wageringStats.wageringStraightSpread.money}})
{{/if}}
You can create a isArray helper that does the check:
Template.layout.helpers({
isArray: function(a){
return Array.isArray(a);
}
});
And use it from your html with:
{{#if isArray someVariable}}
First of all, your if condition is wrong. it is supposed to ==, not =. However, that is not the case, because if of Meteor template does not support boolean operation. Therefore, you will have to have a helper for this
Template.layout.helpers({
checkArray: function() {
// return the result of the comparison of
// team.[0].wageringStats.wageringStraightSpread == array.
// you do need to find the way to compare the array since == is also wrong
// for comparing the array
}
});
{{#if checkArray}}
{{/if}}

How to pass Meteor Spacebars helper with parameter into another helper attribute?

everybody :) For example I have something like this:
{{> someCoolHelper
someParam1='someVal1'
someParam2='someVal2'
someParam3='SomeVal3'
someParam4=someAnotherHelper 'value param to this helper'
}}
So I have a function, that computes some value depending on parameter that can be passed in it. So how can I do this?
as you may read in a forum thread at meteor forum this is not possible by now in spacebars.
We began with a new package for chaining methods and arguments but its not released yet. What you could do is to use the WITH element like
Instead something like:
{{> someCoolHelper
someParam1='someVal1'
someParam2='someVal2'
someParam3='SomeVal3'
someParam4=someAnotherHelper 'value param to this helper'
}}
can be managed by:
{{#with someAnotherHelper 'value param to this helper' }}
{{> someCoolHelper
someParam1='someVal1'
someParam2='someVal2'
someParam3='SomeVal3'
someParam4=this
}}
{{/with}}
I don't like it, but sometimes necessary
Tom
P.S.: Or drop Spacebars and use React - you won't have such limitations there.
The placeholder solution until template sub expressions are available in Spacebars is to create an helper returning the adequate value in JS :
HTML
{{> myTemplate param1="A" param2=param2}}
JS
function someOtherHelper(param){
console.log(param);
}
Template.registerHelper("someOtherHelper", someOtherHelper);
Template.myTemplate.helpers({
param2: function(){
return someOtherHelper("B");
}
});
You can pass the output of a helper to another helper using parentheses. Pretty sure this is what you're after:
http://blazejs.org/guide/spacebars.html#Calling-helpers-with-arguments
You can also pass the output of a helper to a template inclusion or other helper. To do so, use parentheses to show precedence:
{{> Todos_item (todoArgs todo)}}
Here the todo is passed as argument to the todoArgs helper, then the output is passed into the Todos_item template.
Something I did in a recent project uses this functionality to allow conditional rendering of CSS classes to a component (stripped down for brevity):
# global helper to provide ternary operator
Template.registerHelper('ternary', (condition, resultTrue, resultFalse) => {
return condition ? resultTrue : resultFalse
})
# in my-template.js:
Template.My_template.helpers({
isComplete(score) {
return score === 1
}
})
# in my-template.html:
{{> some_component class=(ternary (isComplete this.score) "green" "red")}}

Using a helper with arguments AS a helper argument in Spacebars

So I am trying use a helper as an argument of another helper in Spacebars. In the example below, 'getResultInfo' is a helper that gets data specific to the arguments passed, and 'formatResult' is a helper that formats its result and the results of other helpers.
<template name="example">
{{#each collectionResults}}
Label: {{formatResult getResultInfo this._id 'text'}}
{{/each}}
</template>
The issue I'm having is that Spacebars thinks that the arguments for 'getResultInfo' are the just second and third arguments for 'formatResult'. I'd really like to keep the helper's functions separate (ie. not having to format the result at the end of the 'getResultInfo' and every other helper that I have). Is there any alternate syntax or method of doing what I'm trying to achieve?
I think that you cannot chain two helpers with parameters on the second one like you did. Subsequent parameters will still be interpreted as parameters from the first helper.
I see two ways for solving this problem:
1) you could get rid of the parameters and use the data context provided by each.
each bind the data context to this so in getResultInfo you could just use this._id directly. But you have to remember that you need this data context each time you use this helper. And this pose a problem with the 'text' parameter which does not depend from the data context.
2) you could create a function corresponding to your getResultInfo helper and use it directly in the formatResult helper like this:
getResultHelper = function(id, text) {
//do what you want
};
//bind the function to your getResultInfo (example with a global helper)
Template.registerHelper('getResultInfo', getResultHelper);
//use the function in your template helper
Template.example.helpers({
formatResult: function(format) {
return getResultHelper(this._id, format);
}
});
//and finally your template
<template name="example">
{{#each collectionResults}}
Label: {{formatResult 'text'}}
{{/each}}
</template>
FYI, this is now possible in Meteor 1.2, via Spacebars sub expressions in Blaze.
<template name="example">
{{#each collectionResults}}
Label: {{formatResult (getResultInfo this._id 'text')}}
{{/each}}
</template>

Meteor: Passing more than one value to a template

I want to create a template/js combo similar to the ones below. What I would like is to have two variables available to the 'collection' template
<template name="collection">
Title: {{title}}
<UL>
{{#each items}}
{{> item}}
{{/each}}
</UL>
</template>
<template name="collection_items">
<LI>{{item_title}}</LI>
</template>
Where the javascript function would be something like:
Template.collection.data = function() {
var record = Record.findOne({whatever:value});
return { title: record.title, items: record.items }
}
I've tried using Handlebars' {{#with data}} helper and return an object as above, but that just crashed the template. I've tried creating a 'top level' function like:
Template.collection = function () {... }
but that also crashed the template.
What I'm trying to avoid is having two separate functions (one Template.collection.title, and one Template collection.items) where each of them calls a findOne on the Record collection where really its the same template and one call should suffice.
Any ideas?
Template.collection = function () {... }
Template.collection is not a function, it's an instance and thus an object.
You can type Template.collection in the console to see something essential as well as Template.collection. and autocomplete that to see its methods and fields.
For a #with example, the Todos indeed doen't seem to contain one as you have outlined in your comments. So, an example use of it can be found here:
https://github.com/meteor/meteor/blob/master/packages/templating/templating_tests.js#L75
https://github.com/meteor/meteor/blob/master/packages/templating/templating_tests.html#L92
Here is another example that I tried that works on both the current master and devel branch:
<head>
<title>test</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
{{#with author}}
<h2>By {{firstName}} {{lastName}}</h2>
{{/with}}
</template>
And the JS part of it:
if (Meteor.is_client) {
Template.hello.author = function () {
return {
firstName: "Charles",
lastName: "Jolley"
};
};
}
Any specific reason why you're hoping to avoid two functions?
From your code sample I see one issue: the first template is calling a second template with this line:
{{> item}}
But your second template is not called 'items'. I believe that your second template should be called this way:
<template name="item">
Seems that it would be simple enough to have helper functions for the first and the second. Although I haven't gotten it to work with my own code, I believe the second helper function would want to use the 'this' convention to refer to the collection you're referring to.
Cheers - holling
Tom's answer is correct. I want to just chime in and add that in my scenario the reason why #with was failing was because due to the 'reactive' nature of meteor my first call to load the model resulted in 'undefined' and I didn't check for it. A fraction later it was loaded ok.
The moral is to do something like
var record = Record.findOne({whatever:value})
if (record) {
return record;
} else {
// whatever
return "loading"
}

Resources