Частичное прохождение переменных через руль
В настоящее время я имею дело с handlebars.js в приложении express.js. Чтобы сохранить модульность, я разделил все свои шаблоны на части.
Моя проблема: я не смог найти способ передать переменные через частичный вызов. Допустим, у меня есть частичное, которое выглядит так:
<div id=myPartial>
<h1>Headline<h1>
<p>Lorem ipsum</p>
</div>
Давайте предположим, что я зарегистрировал этот частичный с именем "myPartial". В другом шаблоне я могу сказать что-то вроде:
<section>
{{> myPartial}}
</section>
Это прекрасно работает, часть будет отображаться, как и ожидалось, и я счастливый разработчик. Но то, что мне сейчас нужно, это способ передачи различных переменных через этот вызов, например, для проверки внутри партиала, задан заголовок или нет. Что-то вроде:
<div id=myPartial>
{{#if headline}}
<h1>{{headline}}</h1>
{{/if}}
<p>Lorem Ipsum</p>
</div>
И вызов должен выглядеть примерно так:
<section>
{{> myPartial|'headline':'Headline'}}
</section>
или так.
Я знаю, что я могу определить все данные, которые мне нужны, перед тем, как рендерить шаблон. Но мне нужен способ сделать это, как только что объяснил. Есть ли возможный путь?
7 ответов
Частицы Handlebars принимают второй параметр, который становится контекстом для частичного:
{{> person this}}
В версиях v2.0.0 alpha и выше вы также можете передавать хеш именованных параметров:
{{> person headline='Headline'}}
Вы можете увидеть тесты для этих сценариев: 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
На всякий случай, вот что я сделал, чтобы получить частичные аргументы, вроде. Я создал небольшой помощник, который принимает частичное имя и хэш параметров, которые будут переданы частичному:
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);
});
Ключевым моментом здесь является то, что помощники Handlebars принимают Ruby-подобный хэш аргументов. В коде помощника они входят в последний аргумент функции -options
- в своем hash
член. Таким образом, вы можете получить первый аргумент - частичное имя - и получить данные после этого.
Тогда вы, вероятно, хотите вернуть Handlebars.SafeString
от помощника или используйте "тройной тайник" -{{{
- чтобы избежать двойного побега.
Вот более или менее полный сценарий использования:
<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>
Надеюсь, это поможет... кому-то.:)
Это также можно сделать в более поздних версиях руля, используя key=value
обозначения:
{{> mypartial foo='bar' }}
Позволяет вам передавать определенные значения в ваш частичный контекст.
Это очень возможно, если вы напишите свой собственный помощник. Мы используем кастом $
помощник для выполнения этого типа взаимодействия (и многое другое):
/*///////////////////////
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) );
});
Похоже, вы хотите сделать что-то вроде этого:
{{> person {another: 'attribute'} }}
Иегуда уже дал вам способ сделать это:
{{> person this}}
Но чтобы уточнить:
Чтобы дать вашему частичному элементу свои собственные данные, просто предоставьте ему собственную модель внутри существующей модели, например:
{{> person this.childContext}}
Другими словами, если это модель, которую вы даете своему шаблону:
var model = {
some : 'attribute'
}
Затем добавьте новый объект для партиала:
var model = {
some : 'attribute',
childContext : {
'another' : 'attribute' // this goes to the child partial
}
}
childContext
становится контекстом частичного, как сказал Иегуда - в этом он видит только поле another
, но он не видит (или заботится о поле some
). Если у тебя есть id
в модели верхнего уровня, и повторите id
снова в childContext, это будет работать просто отлично, поскольку частичное видит только то, что внутри childContext
,
Принятый ответ отлично работает, если вы просто хотите использовать другой контекст в своей части. Тем не менее, он не позволяет вам ссылаться на родительский контекст. Чтобы передать несколько аргументов, вам нужно написать свой собственный помощник. Вот рабочий помощник для руля 2.0.0
(другой ответ работает для версий <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) );
});
Затем в своем шаблоне вы можете сделать что-то вроде:
{{renderPartial 'myPartialName' foo=this bar=../bar}}
А в своей части вы сможете получить доступ к этим значениям в виде контекста, например:
<div id={{bar.id}}>{{foo}}</div>
Да, я опоздал, но я могу добавить для пользователей Assemble: вы можете использовать встроенный "parseJSON"
помощник http://assemble.io/helpers/helpers-data.html. (Обнаружено в https://github.com/assemble/assemble/issues/416).
Не уверен, что это полезно, но вот пример шаблона Handlebars с динамическими параметрами, переданными во встроенную часть RadioButtons, и клиентом (браузером), отображающим переключатели в контейнере.
Для меня он отображается с помощью Handlebars на сервере и позволяет клиенту завершить его. С его помощью инструмент форм может предоставлять встроенные данные в Handlebars без помощи помощников.
Примечание. Для этого примера требуется 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"}]'
}}