I work with the ZURB template of Foundation for sites.
I really can't find what is the problem and can't be sure if "this" can be passing to the helper #ifequal (Panini). The partial where the code is :
{{#each #root.content}}
{{#ifequal #key #../key}}
{{#key}}-{{this}} this output the right key and string 'import-fragment'
{{#ifequal this 'import-fragment'}} but never evaluate it equal to true?
{{#key}}-{{this}} nothing here and never call this partial
{{> fragment-router sub-segment-obj=../this }}
{{else}}
all works well from here
{{> main-content sub-segment-obj=../this }}
{{/ifequal}}
{{/ifequal}}
{{/each}}
as you can see in the code, I'm not able to get the string 'import-fragment' = to true {{#ifequal this 'import-fragment'}} even if it's the right string that is evaluated. This is the page where I put content in Front Matter YAML format :
---
category: marketing
content:
###################################### SECTION ##########################################
web-stats: import-fragment # why this doesn't equal import-fragment???
# all following this works
web-stats-in-page-way:
sub-sections:
################### ARTICLE #######################
First article:
...
Is someone can see what I missed?
Thank you in advance. I will payback to the next.
Related
In my js file, I pass a JSON object with two keys - {'tests': tests, 'isComplete': isComplete}
In my handlebars file, I want to display the tests object based on each test status. At the same time, there's another condition for which I added a helper named 'isRequired' that I want to check the test against only if isComplete is not true.
{{#if isComplete}}
{{#each tests}}
{{#isRequired this}}
// display data
{{/isRequired}}
{{/each}}
{{else}}
{{#each tests}}
// display data
{{/each}}{{/if}}
This code has the duplicate code to display data. I'm still learning handlebars and not sure how to eliminate this redundant code block. Can you help me how I can refactor this? Thank you!
I would probably solve this by adding an isComplete parameter to your isRequired helper. You have not provided the code for your helper, but I imagine it would end up looking something like this:
Handlebars.registerHelper('isRequired', function (context, isComplete, options) {
if (!isComplete) { return options.fn(context); }
/* rest of isRequired implementation here */
});
Your template would then be updated as follows:
{{#each tests}}
{{#isRequired this ../isComplete}}
// display data
{{/isRequired}}
{{/each}}
Note that this implementation applies the isRequired logic only if isComplete is true. This is the same rules as exist in your template code sample. However, these rules appear to contradict the text of your question, which specifies that isRequired should be applied "only if isComplete is not true". If these are the requirements we must meet, we need only remove the not operator from our new guard clause:
if (isComplete) { return options.fn(context); }
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")}}
Just starting with Meteor, and going through the Meteor Tutorial by Matthew Platts.
In this tutorial, as well as in the official Meteor Documentation, there are many references to the concept of data context, but I can't seem to find a cristal clear definition / explanation (with examples) of what this is.
For instance, in the 2.4.3 Rendering Data with Helpers section, we read:
Notice that inside of the #each block we go {{name}}, even though
we have no name helper defined. This is because the data context
changes inside the #each block. We loop through each item in the
teams array, and since each item has a “name” attribute Meteor will
automatically create a {{ name }} helper.
UPDATE: Actually, just reading through the end of this very section, the author recommends a resource that makes things pretty clear: A Guide to Meteor Templates & Data Contexts. Still no accurate definition though.
So, in Meteor, what is data context exactly?
I'll try to explain as much as I know, correct me if I'm wrong.
I'll explain using following snippet:
<template name="posts">
{{#each posts}}
<p>{{name}}</p>
{{/each}}
</template>
Let's assume it will display all the posts names from a blog:
First Post
Second post
Third post
..........
..........
I assume you know the concept of helpers and events.
In the above snippet, in general for {{name}}, meteor searches for the helper called name in helpers:
Template.posts.helpers({
name: function(){
return "dummy text";
}
});
If it finds any, it runs that helpers and displays the value.
So here, it outputs:
dummy text
dummy text
dummy text
...........
But if it doesn't find any helpers, it will search in data context.
Let's assume for posts we're returning some data:
Template.posts.helpers({
posts: function(){
return Posts.find().fetch();
}
});
The data we're sending to posts helper looks like this:
{name: "First post", _id: "xxx", ......},
{name: "Second post", _id: "yyy", ......}
{name: "Third post", _id: "zzz", ......}
.................
In the code for {{#each posts}}, it loops through every object and displays name property("First Post","Second Post,"Third Post").
It displays name property because it doesn't find any helper for name, and then it searches in the current data context and found property with the same name name and displays that.
Data context in helpers and events
Let's take the same snippet and add a delete button:
<template name="posts">
{{#each posts}}
<p>{{name}}</p>
<button>Delete Post</button>
{{/each}}
</template>
It displays like below:
First Post <Delete Post>
Second post <Delete Post>
Third post <Delete Post>
..........
..........
In the events:
Template.posts.events({
'click button': function(){
console.log(this)
Posts.remove({_id: this._id });
}
})
Here, when you click on any delete button, it will delete respective post.
Here we're using this._id: this means data context.
this will give you the data that the helper takes as input to display.
For example, if you click on the delete button beside First Post, then in the events it will give you following data as this:
{name: "First post", _id: "xxx", ......},
because that is the data context available when it displays that content.
Same if you click on the button beside second post:
{name: "Second post", _id: "yyy", ......},
And same goes with the helpers too.
I hope this helps at least someone out there.
This is not easy to explain. Like you I used it in tutorial without knowing it. After some research I found the best explanation, a visual one. You can have a look at Discover Meteor article about "Templates & Data Contexts". Hope it will clarify your mind about it.
A data context can be one of 3 things: (unless I've missed some)
A cursor, i.e. the result of a Collection.find()
An array of objects, i.e. just some array or the result of a Collection.find().fetch()
An individual object, i.e. { _id: "123", name: "Orthoclase E. Feldspar" }
{{#each foo}} loops over a cursor or array context and changes the context to an individual object. {{#with bar}} just says which helper to use (in this case bar) to set the data context.
During development, but especially while learning Meteor, it helps to have console.log(this) at the top of your helper code just to double check what the data context is. It is this.
I am wondering how to solve this problem:
I have a template which contains some text with some template helpers inside:
<template>Hello {{who}}, the wheather is {{weather}}</template>
Now I need to change the content of the template dynamically at runtime, while maintaining the helper functionality. For example I would need it like this:
<template>Oh, the {{weather}}. Good evening {{who}}</template>
The text changes and the helpers are needed at different positions. Think of an application where users can create custom forms with placeholders for certain variables like the name of the user who fills out the form. Basically, the content of the template is stored in a mongo document and needs to be turned into a template at runtime, or an existing template needs to be changed.
How to approach this? Can I change the contents of a template at runtime?
To solve this use case you need to use two techniques.
Firstly you need to be able to change the template reactivel. To do this you can use Template.dynamic. eg:
{{> Template.dynamic template=helperToReturnName [data=data] }}
See here: http://docs.meteor.com/#/full/template_dynamic
Now that you can change template, you need to be able to create new templates on the fly from you database content. This is non trivial, but it's possible if you're willing to write code to create them, like this:
Template.__define__("postList", (function() {
var view = this;
return [
HTML.Raw("<h1>Post List</h1>\n "),
HTML.UL("\n ", Blaze.Each(function() {
return Spacebars.call(view.lookup("posts"));
},
function() {
return [ "\n ", HTML.LI(Blaze.View(function() {
return Spacebars.mustache(view.lookup("title"));
})), "\n " ];
}), "\n ")
];
}));
That code snippet was taken from this article on Meteorhacks, and the article itself goes into far more detail. After reading the article you'll be armed with the knowledge you need to complete the task...
Just have a helper dynamically build the entire string (remembering that this refers to the current data context):
Template.foo.helpers({
dynamicString: function(switch){
if ( switch == 1) return "Hello "+this.who+", the wheather is "+this.weather;
else return "Oh, the "+this.weather+". Good evening "+this.who;
}
});
Then in your template:
<template name="foo">
{{dynamicString}}
</template>
Alternatively, just use {{#if variable}} or {{#unless variable}} blocks to change the logic in your template. Much, much simpler.
<template name="foo">
{{#if case1}}
Hello {{who}}, the wheather is {{weather}}
{{else}}
Oh, the {{weather}}. Good evening {{who}}
{{/if}}
</template>
You can always have a template helper that computes the necessary boolean variables (e.g. case1).
I am working on an edit form that has two paths. One is when the user clicks a "New" button, the other is when they click "Edit".
When they click "New", the code sets a form_id Session var to null and a client_id session variable to null, then does a Router.go('formEdit') to load the formEdit template/route.
In the formEdit.js, I do a reactive Template helper (I think that's what they are called, but anyway) like so:
Template.formEdit.form = function() {
var form;
if (Session.equals('form_id', null)) {
// Create empty form
form = {
title: null,
client_id: Session.get('client_id'),
header_fields: [],
form_fields: []
};
} else {
// Load form
form = Forms.findOne({_id: Session.get('form_id')});
}
return form;
}
Basically I check if the form_id was set or not, if so I load it from the Forms collection, if not I create a blank one. I thought this would be pretty simple, really.
The problem is that the created/found form object does not behave in a "reactive" way. If I add header_fields or form_fields the subsequent template code never updates. Both are in a {{#each}} like so:
<template name="formEdit">
...
{{#each header_fields}}
{{> headerFieldOutput}}
{{/each}}
...
{{#each form_fields}}
{{> formFieldOutput}}
{{/each}}
</template>
How do I make it such that I can push header_fields and form_fields onto the form and have the underlying template reactively update the {{#each}}'s?
I think you're going about it a little differently than what the reactive programming methodology in Meteor is expecting.
You're putting the 'display' logic in your template helper, rather than using the template scaffolding itself to do it.
So, declare a very simple template helper, something like this:
Template.formEdit.form = function () {
return forms.findOne(Session.get("form_id"));
};
And then, in your template scaffolding have something like this:
{{#if form}}
{{#with form}}
{{#each header_fields}}
etc...
{{/with}}
{{#else}}
[[insert your blank form scaffolding in here]]...
{{/if}}
Then, as you set your Session form_id variable, you can set it to null to invoke the {{#else}} portion.
There are more details than this (logic in the form submit click handler to identify if you are performing an update or an insert, for example) but hopefully you get the gist of it from this.
You should try to gain a better understanding about how cursors and reactive computations work, as it will help you better understand how to best use the reactive methodology. A good starting place is the parties example (watch the video and walk through the code manually). It's similar to what you're doing, and shows a good way of building your templates for when you don't have a 'selected' object.
Hope this helps!