I'm using Foundation for Sites which uses Panini and Handlebars for JS templating. I need an {{#ifequal}} statement that includes a js variable so that I can compare a URL parameter to a JSON
What I have right now:
{{#ifequal "Canada" this.destination}}
//do the thing
{{/ifequal}}
What I need is something like this:
{{#ifequal <script>document.write(destId)</script> this.destination}}
//do the thing
{{/ifequal}}
The js var "destId" is assigned earlier in the page when it's pulled out of the URL parameters, but of course I can't include the script inside the handlebars. If there's a way to pass a URL parameter directly into a handlebar that would also work.
as noted before on this question (link is here):
Handlebars partials take a second parameter which becomes the context for the partial:
{{> person this}}
In versions v2.0.0 alpha and later, you can also
pass a hash of named parameters:
{{> person headline='Headline'}}
You can see the tests for these
scenarios:
https://github.com/wycats/handlebars.js/blob/ce74c36118ffed1779889d97e6a2a1028ae61510/spec/qunit_spec.js#L456-L462
https://github.com/wycats/handlebars.js/blob/e290ec24f131f89ddf2c6aeb707a4884d41c3c6d/spec/partials.js#L26-L32
Related
Using assignVar and getVar (Bigcommerce Handlebars helpers) I'm trying to create and insert a javascript variable like so:
<script>var exampleVar = "string";</script>
{{ assignVar "exampleVar" exampleVar}}
The result when using {{ getVar"exampleVar" }} is that it throws a "not a string error".
I tried {{ assignVar "exampleVar" "exampleVar"}} which outputs "exampleVar" (minus the quotes). I would like it to output "string" (minus the quotes).
Any thoughts?
You can't. Handlebars is already compiled in the server before it reaches the front end side. If the logic is done in javascript, then you should display the result via javascript too.
In a Template Helper I get the current path from Iron.Router (iron:router) as follows:
Router.current().route.path(this);
This works fine, unless the route path does contain parameters (e.g. /client/:_id/edit). In that case the path() function returns null.
How do I get the current path within a Template Helper, when the route contains parameters?
There are posts around covering the issue but the solution mentioned there seem not to fit.
I'm using Meteor 1.1.5 with iron:router1.0.7
According to this iron-router/issues/289 there are problems when the path contains parameters. The suggestion to use Iron.Location.get().path This works well for me.
I've seen a few answers on how to pass a parameter using iron:router as the third parameter, for example: href="{{pathFor 'article' _id=this._id }}"
What I would like to do is pass a parameter as the second variable (where 'article' is in the example above).
I have a collection of posts that contain a title, a body, and a type. There are three types of articles in the project I'm working on, and each type needs to be routed to a different template because the formatting is significantly different.
What I would like to be able to do is route to a particular url based on the type. An example that captures my intent but doesn't work would be this:
link
One of the "types" is "inquiry", and the route looks like this:
#route "inquiryPost",
path: "inquiry/:_id"
data: ->
Posts.findOne #params._id
waitOn: ->
[
Meteor.subscribe "posts"
]
I've tried using a helper to pass the value into the pathFor, but that didn't work either:
path: ->
type = #type
"pathFor '#{type}'"
...with this on the front end:
link
I can think of a few work arounds, but it seems to me like there should be an easier way to pass in parameters...
So, is it possible to pass in parameters into the second value of a pathFor?
Try with
<template name="example">
link
</template>
Where type is the helper
Template.example.examples({
type:function(){
return type;
}
})
Also you can try with this for example
link with many parameters
Here you where accessing for example to the route
/myRoute/type/rewr8671qew for example
I want to give my users the possibility to create document templates (contracts, emails, etc.)
The best option I figured out would be to store these document templates in mongo (maybe I'm wrong...)
I've been searching for a couple of hours now but I can't figure out how to render these document template with their data context.
Example:
Template stored in Mongo: "Dear {{firstname}}"
data context: {firstname: "Tom"}
On Tom's website, He should read: "Dear Tom"
How can I do this?
EDIT
After some researches, I discovered a package called spacebars-compiler that brings the option to compile to the client:
meteor add spacebars-compiler
I then tried something like this:
Template.doctypesList.rendered = ->
content = "<div>" + this.data.content + "</div>"
template = Spacebars.compile content
rendered = UI.dynamic(template,{name:"nicolas"})
UI.insert(rendered, $(this).closest(".widget-body"))
but it doesn't work.
the template gets compiled but then, I don't know how to interpret it with its data context and to send it back to the web page.
EDIT 2
I'm getting closer thanks to Tom.
This is what I did:
Template.doctypesList.rendered = ->
content = this.data.content
console.log content
templateName = "template_#{this.data._id}"
Template.__define__(templateName, () -> content)
rendered = UI.renderWithData(eval("Template.#{templateName}"),{name:"nicolas"})
UI.insert(rendered, $("#content_" + this.data._id).get(0))
This works excepted the fact that the name is not injected into the template. UI.renderWithData renders the template but without the data context...
The thing your are missing is the call to (undocumented!) Template.__define__ which requires the template name (pick something unique and clever) as the first argument and the render function which you get from your space bars compiler. When it is done you can use {{> UI.dynamic}} as #Slava suggested.
There is also another way to do it, by using UI.Component API, but I guess it's pretty unstable at the moment, so maybe I will skip this, at least for now.
Use UI.dynamic: https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/
It is fairly new and didn't make its way to docs for some reason.
There are few ways to achieve what you want, but I would do it like this:
You're probably already using underscore.js, if not Meteor has core package for it.
You could use underscore templates (http://underscorejs.org/#template) like this:
var templateString = 'Dear <%= firstname %>'
and later compile it using
_.template(templateString, {firstname: "Tom"})
to get Dear Tom.
Of course you can store templateString in MongoDB in the meantime.
You can set delimiters to whatever you want, <%= %> is just the default.
Compiled template is essentially htmljs notation Meteor uses (or so I suppose) and it uses Template.template_name.lookup to render correct data. Check in console if Template.template_name.lookup("data_helper")() returns the correct data.
I recently had to solve this exact (or similar) problem of compiling templates client side. You need to make sure the order of things is like this:
Compiled template is present on client
Template data is present (verify with Template.template_name.lookup("data_name")() )
Render the template on page now
To compile the template, as #apendua have suggested, use (this is how I use it and it works for me)
Template.__define__(name, eval(Spacebars.compile(
newHtml, {
isTemplate: true,
sourceName: 'Template "' + name + '"'
}
)));
After this you need to make sure the data you want to render in template is available before you actually render the template on page. This is what I use for rendering template on page:
UI.DomRange.insert(UI.render(Template.template_name).dom, document.body);
Although my use case for rendering templates client side is somewhat different (my task was to live update the changed template overriding meteor's hot code push), but this worked best among different methods of rendering the template.
You can check my very early stage package which does this here: https://github.com/channikhabra/meteor-live-update/blob/master/js/live-update.js
I am fairly new to real-world programming so my code might be ugly, but may be it'll give you some pointers to solve your problem. (If you find me doing something stupid in there, or see something which is better done some other way, please feel free to drop a comment. That's the only way I get feedback for improvement as I am new and essentially code alone sitting in my dark corner).
As we all know, Meteor's initial payload sent to the client comprises (in production) a concatenated javascript file containing the Meteor platform, packages, and all templates parsed into Meteor's reactive templating system. Server-side rendering, where the templates are rendered to HTML and sent to the client in the initial payload, is on its way but doesn't have an expected release date yet.
I'm looking for a way to "hack" or approximate server-side rendering given the available functionality in Meteor 0.8.x. Specifically, I want to:
enable the page to render its initial contents without first waiting for the several hundred KB Meteor platform javascript file to be downloaded and parsed.
alternatively, modify Meteor so it only sends the templates it needs to render the initial request in the javascript payload, and fetches the remaining templates once render is complete.
The use case is http://q42.com. I recognise Meteor isn't the best fit for static websites like this one but I want to try and see how far I can get anyway. Right now the Meteor platform JS file is over 600 KB in size (±200 KB gzipped) and I'd like to reduce this size if possible.
Note: I'm aware of and already using Arunoda's fast-render package, which is intended to send data with the initial payload. In this case I want to cut down on time-to-first-render by also getting the templates themselves down faster.
This is a little bit tricky. But there are some things you could do. This may not be the beeest way to do it but it could help you get started somehow.
Meteor is build with many packages as 'default', sometimes some are not needed. You can remove the standard-app-packages and add the packages (that you need and use manually) listed here: https://github.com/meteor/meteor/blob/devel/packages/standard-app-packages/package.js
To cut down the templates you would have to include the bare templates that you use and include the other template's separately and perhaps send down the Template information via a Collection, using a live observer handle to initiate the templates
You would have to 'render' the templates on the server side or store them manually in your collection using Spacebars.compile from the spacebars-compiler package which is a little tricky but you could have it done decently:
This should give you a rough idea, not sure how to get passed the 'eval' bit of it though:
HTML file in /private/template.html
<template name="test">
Hello {{name}}
</template>
JS file in /private/template.js
Template.test.name = function() { return "Bob" }
Server side code
var collection = new Meteor.Collection("templates");
var templateData = Assets.getText("template.html");
var templateJs = Assets.getText("template.js");
var compiled = Spacebars.compile(templateData).toString();
var jsData = templateJs;
collection.insert({templateName:"test", data: templateData, js: templateJs});
Client Side code
collection.find().observeChanges({
added: function(id, fields) {
var template = fields.data,
name = fields.name,
js = fields.js;
Template["name"] = UI.Component.extend({
kind: "name",
render: eval(template),
});
eval(js);
}
});
Then just subscribe to the collection asking for your template and it should exist. If you use iron-router I think (not sure) you could make the subscription wait before the template is rendered so you could have it work.
Again this is just a 'hacky' solution, one thing I personally don't like about it is the use of eval, but javascript needs to run somehow...
You could loop through files in a particular folder using fs = Npm.require('fs') to render each template too.
One alternative would be to inject a 'script' tag calling the compiled js template and template helpers to let the template exist.