Je traite actuellement avec handlebars.js dans une application express.js. Pour garder les choses modulaires, je divise tous mes modèles en partiels.
Mon problème: Je ne pouvais pas trouver un moyen de passer des variables via une invocation partielle. Disons que j'ai un partiel qui ressemble à ceci:
<div id=myPartial>
<h1>Headline<h1>
<p>Lorem ipsum</p>
</div>
Supposons que j'ai enregistré ce partiel avec le nom 'myPartial'. Dans un autre modèle, je peux ensuite dire quelque chose comme:
<section>
{{> myPartial}}
</section>
Cela fonctionne bien, le partiel sera rendu comme prévu et je suis un développeur heureux. Mais ce dont j'ai maintenant besoin, c'est d'un moyen de passer différentes variables à travers cette invocation, de vérifier dans un partiel par exemple, si un titre est donné ou non. Quelque chose comme:
<div id=myPartial>
{{#if headline}}
<h1>{{headline}}</h1>
{{/if}}
<p>Lorem Ipsum</p>
</div>
Et l'invocation devrait ressembler à ceci:
<section>
{{> myPartial|'headline':'Headline'}}
</section>
ou alors.
Je sais que je suis capable de définir toutes les données dont j'ai besoin avant de générer un modèle. Mais j'ai besoin d'un moyen de le faire comme je viens de l'expliquer. Y a-t-il un moyen possible?
Les partiels du guidon prennent un deuxième paramètre qui devient le contexte du partiel:
{{> person this}}
Dans les versions v2.0.0 alpha et supérieures, vous pouvez également transmettre un hachage de paramètres nommés:
{{> person headline='Headline'}}
Vous pouvez voir les tests de ces scénarios: 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
Juste au cas où, voici ce que j'ai fait pour obtenir des arguments partiels, en quelque sorte. J'ai créé un petit assistant qui prend un nom partiel et un hachage de paramètres qui seront transmis au partiel:
Handlebars.registerHelper('render', function(partialId, options) {
var selector = 'script[type="text/x-handlebars-template"]#' + partialId,
source = $(selector).html(),
html = Handlebars.compile(source)(options.hash);
return new Handlebars.SafeString(html);
});
L’essentiel ici est que les guidons acceptent un hachage d’arguments semblable à Ruby . Dans le code d’assistance, ils font partie du dernier argument de la fonction —options
— dans son membre hash
. De cette façon, vous pouvez recevoir le premier argument - le nom partiel - et récupérer les données par la suite.
Ensuite, vous voudrez probablement renvoyer un Handlebars.SafeString
de l’assistant ou utiliser "triple-stash" —{{{
– pour l’empêcher de s’échapper deux fois.
Voici un scénario d'utilisation plus ou moins complet:
<script id="text-field" type="text/x-handlebars-template">
<label for="{{id}}">{{label}}</label>
<input type="text" id="{{id}}"/>
</script>
<script id="checkbox-field" type="text/x-handlebars-template">
<label for="{{id}}">{{label}}</label>
<input type="checkbox" id="{{id}}"/>
</script>
<script id="form-template" type="text/x-handlebars-template">
<form>
<h1>{{title}}</h1>
{{ render 'text-field' label="First name" id="author-first-name" }}
{{ render 'text-field' label="Last name" id="author-last-name" }}
{{ render 'text-field' label="Email" id="author-email" }}
{{ render 'checkbox-field' label="Private?" id="private-question" }}
</form>
</script>
J'espère que ça aide… quelqu'un. :)
Ceci est très possible si vous écrivez votre propre aide. Nous utilisons un assistant personnalisé _$
_ pour réaliser ce type d'interaction (et plus encore):
_/*///////////////////////
Adds support for passing arguments to partials. Arguments are merged with
the context for rendering only (non destructive). Use `:token` syntax to
replace parts of the template path. Tokens are replace in order.
USAGE: {{$ 'path.to.partial' context=newContext foo='bar' }}
USAGE: {{$ 'path.:1.:2' replaceOne replaceTwo foo='bar' }}
///////////////////////////////*/
Handlebars.registerHelper('$', function(partial) {
var values, opts, done, value, context;
if (!partial) {
console.error('No partial name given.');
}
values = Array.prototype.slice.call(arguments, 1);
opts = values.pop();
while (!done) {
value = values.pop();
if (value) {
partial = partial.replace(/:[^\.]+/, value);
}
else {
done = true;
}
}
partial = Handlebars.partials[partial];
if (!partial) {
return '';
}
context = _.extend({}, opts.context||this, _.omit(opts, 'context', 'fn', 'inverse'));
return new Handlebars.SafeString( partial(context) );
});
_
Cela peut également être fait dans les versions ultérieures du guidon en utilisant la notation key=value
:
{{> mypartial foo='bar' }}
Vous permettant de transmettre des valeurs spécifiques à votre contexte partiel.
Référence: contexte différent pour partiel # 182
La réponse acceptée fonctionne très bien si vous souhaitez simplement utiliser un contexte différent dans votre partial. Cependant, il ne vous permet pas de référencer le contexte parent. Pour transmettre plusieurs arguments, vous devez écrire votre propre aide. Voici un assistant qui fonctionne pour le guidon 2.0.0
(l’autre réponse fonctionne pour les versions <2.0.0
):
Handlebars.registerHelper('renderPartial', function(partialName, options) {
if (!partialName) {
console.error('No partial name given.');
return '';
}
var partial = Handlebars.partials[partialName];
if (!partial) {
console.error('Couldnt find the compiled partial: ' + partialName);
return '';
}
return new Handlebars.SafeString( partial(options.hash) );
});
Ensuite, dans votre modèle, vous pouvez faire quelque chose comme:
{{renderPartial 'myPartialName' foo=this bar=../bar}}
Et dans votre partie, vous pourrez accéder à ces valeurs en tant que contexte comme:
<div id={{bar.id}}>{{foo}}</div>
On dirait que vous voulez faire quelque chose comme ça:
{{> person {another: 'attribute'} }}
Yehuda vous a déjà donné un moyen de le faire:
{{> person this}}
Mais pour clarifier:
Pour donner à votre partiel ses propres données, il suffit de lui donner son propre modèle dans le modèle existant, comme suit:
{{> person this.childContext}}
En d’autres termes, s’il s’agit du modèle que vous donnez à votre modèle:
var model = {
some : 'attribute'
}
Ajoutez ensuite un nouvel objet à donner au partiel:
var model = {
some : 'attribute',
childContext : {
'another' : 'attribute' // this goes to the child partial
}
}
childContext
devient le contexte du partiel, comme dit Yehuda - en ce sens, il ne voit que le champ another
, mais il ne voit pas (ni ne se soucie du champ some
). Si vous avez id
dans le modèle de niveau supérieur et que vous répétez id
dans childContext, cela fonctionnera parfaitement, car le partiel ne verra que ce qui se trouve à l'intérieur de childContext
.
Oui, j’étais en retard, mais je peux ajouter pour Assembler utilisateurs: vous pouvez utiliser buil-in "parseJSON"
helper http: //assemble.io/helpers/helpers-data.html . (Découvert dans https://github.com/assemble/assemble/issues/416 ).
Vous n'êtes pas sûr que cela soit utile, mais voici un exemple de modèle Handlebars avec des paramètres dynamiques transmis à un partiel RadioButtons en ligne et au client (navigateur) affichant les boutons radio du conteneur.
Pour mon utilisation, il est rendu avec le guidon sur le serveur et permet au client de le terminer. Grâce à lui, un outil de formulaire peut fournir des données en ligne au guidon sans aide.
Note: Cet exemple nécessite jQuery
{{#*inline "RadioButtons"}}
{{name}} Buttons<hr>
<div id="key-{{{name}}}"></div>
<script>
{{{buttons}}}.map((o)=>{
$("#key-{{name}}").append($(''
+'<button class="checkbox">'
+'<input name="{{{name}}}" type="radio" value="'+o.value+'" />'+o.text
+'</button>'
));
});
// A little test script
$("#key-{{{name}}} .checkbox").on("click",function(){
alert($("input",this).val());
});
</script>
{{/inline}}
{{>RadioButtons name="Radio" buttons='[
{value:1,text:"One"},
{value:2,text:"Two"},
{value:3,text:"Three"}]'
}}