One of my route is defined like this:
society_mybundle_searchpage:
pattern: /search/cp/{cp}
defaults: { _controller: SocietyMyBundle:Search:searchByCP }
So it needs one parameter: {cp}.
Now I'd like to create a form with an input widget. So my code is like that:
<form onsubmit="return search();" action="#">
{{ form_rest(form) }}
</form>
(Nothing specific, I let symfony do all the work for me). Note that this form calls a JS function: search(). So here's my code in twig:
<script type="text/javascript">
<!--
function verif_formulaire(){
/* some code to get the value of the cp */
...
/* then: */
ss="{{ path('society_mybundle_searchpage', {'cp': '+cp+'}) }}";
return true;
}
-->
</script>
The output is:
function verif_formulaire(){
ss="/symfony/web/app_dev.php/pizzas/search/cp/+tt+";
return true;
}
This is not the output I need. I want the output to be exactly like that this:
function verif_formulaire(){
ss="/symfony/web/app_dev.php/pizzas/search/cp/"+tt+"/";
return true;
}
How shall I proceed?
My solution was: implement a custom url_decode function in twig (very easy).
Then use the format() function.
Here's the result:
window.location ="{{ path('my_path', {'cp': "%s" }) | url_decode | format('"+monCP+"') | raw }}";
Explanation: path('my_path', {'cp': "AAAA" }) will generate an URL like '/mypath/cp/AAAA/' thus path('my_path', {'cp': "%s" }) will generate an URL like '/mypath/cp/%s/'
But the '%s' will be escaped. So I decode it through '| url_decode' :
path('my_path', {'cp': "%s" }) | url_decode
Will generate proper string '/mypath/cp/%s/'.
Then I use the format() function to pass a string.
Example: '"/mypath/cp/%s/" | format('OLIVIER')' will give '"/mypath/cp/OLIVIER/"'
So, here, I pass a specific string: '"+monCP+"' (watch carefully the quotes and double quotes).
So: '"/mypath/cp/%s/" | format('"+monCP+"')' will give '/mypath/cp/"+monCP+"/'
Last problem: this whole string is again escaped. This time, a classical "| raw" is enough.
Thus, to conclude, this:
var xx ="{{ path('my_path', {'cp': "%s" }) | url_decode | format('"+monCP+"') | raw }}";
Will result in full normal JavaScript code:
var xx ="/my-symfony-url/cp/"+monCP+"/";
This may look complex, but wow. No external JavaScript file needed. This is what I wanted. Just pure fast Symfony 2 php-generated cache. I propably could make this a Twig macro or something.
As I can see you need generate route in JS. So maybe you need a FOSJsRoutingBundle?
Related
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")}}
I'd like to be able to call (global) template helpers from inclusion template tags.
So this works;
Static version:
{{>volcanoTable pagination=5)}}
But i'd like to get the value of pagination per user by using Template helper function named getPref(key,defaultvalue).
"Dynamic version":
{{>volcanoTable pagination=getPref("pagination",5) }}
which gives error:
Expected space
...ue pagination=getPref('a',5) )}}
Also tried different versions, but they didn't work either;
like {{>volcanoTable pagination=getPref "pagination" "5" }}
Or is there another way to get the same desired results?
You can just create a helper which returns a context object. For example:
Template.myTemplate.helpers({
myPagination: function(n) {
// extract the default pagination for the user
var pagination = Meteor.user().profile.pagination;
if (pagination) {
return {pagination: pagination};
} else {
return {pagination: n};
}
}
});
Which you can use like this:
<template name='myTemplate'>
{{> volcanoTable myPagination 6}}
</template>
In this case, the volcanoTable would get a context of {pagination: 6} only if there was no default pagination property for the user. Of course you could make myPagination a global helper if it's useful outside of this template.
Currently I have the following in a package:
Template.layout.onRendered(function() {
//Do stuff when the template called "layout" is rendered
});
But I would like to make the template name user configurable. Something like:
var templateName = 'customLayout';
Template.{templateName}.onRendered(function() {
//Do stuff when the template called "customLayout" is rendered
});
Any help in the right direction would be great!
In JavaScript you can use the square brackets syntax to do that:
Template['customLayout'].onRendered( [...] )
'customLayout' above can be an arbitrary expression.
From Meteor 0.8.2, you can write this:
var myTemplate='foo';
{{> UI.dynamic template=myTemplate}}
https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/
I'm definitely missing something about the way Handlebars works. I need to call different partials depending on the value of a variable. Currently the only way I've found to do it is this:
<template name="base">
{{#if a}}{{> a}}{{/if}}
{{#if b}}{{> b}}{{/if}}
{{#if c}}{{> c}}{{/if}}
</template>
And in the corresponding JS:
Template.base.a = function () {
return (mode === "a");
}
Template.base.b = function () {
return (mode === "b");
}
Template.base.c = function () {
return (mode === "c");
}
...which strikes me as extremely verbose. What I'd really like to do is something like:
<template name="base">
{{> {{mode}} }}
</template>
In other words, the value of mode would be the name of the partial that is called.
This seems like it must be a very common use-case, but I can't find any examples of this online. Where have I gone wrong?
The partials are stored in Handlebars.partials so you can access them by hand in your own helper. There are a few tricky bits here though:
The contents of Handlebars.partials can be strings or functions so you have to compile the partials on first use.
Handlebars doesn't know if the partial will be text/plain or text/html so you'll need to call your helper in {{{...}}} or {{...}} as appropriate.
This stuff isn't exactly documented (at least not anywhere that I can find) so you have to reverse engineer the Handlebars source and fumble about with console.log(arguments) to figure out how to use Handlebars.partials.
You have to pass this by hand when you call the helper.
Fear not, it isn't really that complicated. Something simple like this:
Handlebars.registerHelper('partial', function(name, ctx, hash) {
var ps = Handlebars.partials;
if(typeof ps[name] !== 'function')
ps[name] = Handlebars.compile(ps[name]);
return ps[name](ctx, hash);
});
should do the trick. Then you can say:
{{{partial mode this}}}
and get on with more interesting things.
Demo: http://jsfiddle.net/ambiguous/YwNJ3/2/
Update for 2016: Version 3 of handlebars added Dynamic Partials. From the docs:
It's possible to dynamically select the partial to be executed by using sub expression syntax.
{{> (whichPartial) }}
Will evaluate whichPartial and then render the partial whose name is returned by this function.
Subexpressions do not resolve variables, so whichPartial must be a function. If a simple variable has the partial name, it's possible to resolve it via the lookup helper.
{{> (lookup . 'myVariable') }}
In my Handlebars template I check for the existence of a variable, and render some text if it's there:
{{#if foo}}
some text
{{/if}}
This works fine if foo is text or if foo is numeric but not zero. But if
var foo = 0;
then {{#if foo}} returns false.
This appears to be yet another Javascript oddity, because Javascript itself behaves the same way. In Javascript code, though, you could get around this by checking if the variable is 'undefined'.
How can I do the same thing in Handlebars?
I could write an {{#exists}} helper, but I was hoping there was something built in.
There is something built in for this:
{{#if foo includeZero=true}}
foo!
{{/if}}
This displays foo! when foo is 0.
I would go one better and provide a case for the {{else}} condition...
/**
* The {{#exists}} helper checks if a variable is defined.
*/
Handlebars.registerHelper('exists', function(variable, options) {
if (typeof variable !== 'undefined') {
return options.fn(this);
} else {
return options.inverse(this);
}
});
Now you can have:
{{#exists myvar}}
<p>Value of myvar is ... {{myvar}}</p>
{{else}}
<p>Please supply a myvar</p>
{{/exists}}
I just went ahead and wrote an {{#exists}} helper. But if someone has a better solution, please post it.
/**
* The {{#exists}} helper checks if a variable is defined.
*/
Handlebars.registerHelper('exists', function(variable, options) {
if (typeof variable !== 'undefined') {
return options.fn(this);
}
});
If anyone gets this error "Expecting 'ID', 'DATA', got 'SEP'" using #Shane method make sure you have no spaces in:
{{ /exist }}
And change it to this:
{{/exist}}