Передача переменных через парные части
В настоящее время я имею дело с 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>
И invokation должен выглядеть примерно так:
<section>
{{> myPartial|'headline':'Headline'}}
</section>
или так.
Я знаю, что я могу определить все данные, которые мне нужны, прежде чем я создам шаблон. Но мне нужен способ сделать это, как только что объяснил. Есть ли способ?
Ответы
Ответ 1
Партии парниковых пар берут второй параметр, который становится контекстом для частичного:
{{> 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
Ответ 2
Это очень возможно, если вы напишете своего помощника. Мы используем специальный $
помощник для выполнения такого типа взаимодействия (и более):
/*///////////////////////
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) );
});
Ответ 3
На всякий случай, вот что я сделал, чтобы получить частичные аргументы, вроде. Ive создал небольшой помощник, который принимает частичное имя и хэш параметров, которые будут переданы частичным:
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 принимают рубиновый хэш аргументов. В хелперном коде они входят как часть функций last argument - options
- в свой член hash
. Таким образом, вы можете получить первый аргумент - частичное имя - и получить данные после этого.
Затем вы, вероятно, захотите вернуть Handlebars.SafeString
из помощника или использовать "triple-stash" - {{{
- для предотвращения двойного экранирования.
Вот более или менее полный сценарий использования:
<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>
Надеюсь, это поможет... кому-то.:)
Ответ 4
Это также можно сделать в более поздних версиях рулей с использованием обозначения key=value
:
{{> mypartial foo='bar' }}
Позволяет передавать конкретные значения в ваш частичный контекст.
Ссылка: Контекст для частичного # 182
Ответ 5
Принятый ответ отлично работает, если вы просто хотите использовать другой контекст в частичном. Однако он не позволяет ссылаться на какой-либо родительский контекст. Чтобы передать несколько аргументов, вам нужно написать свой собственный помощник. Здесь рабочий помощник для Handlebars 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>
Ответ 6
Похоже, вы хотите сделать что-то вроде этого:
{{> 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
.
Ответ 7
Да, я опоздал, но я могу добавить для пользователей Assemble: вы можете использовать buil-in "parseJSON"
helper http://assemble.io/helpers/helpers-data.html. (Открыто в https://github.com/assemble/assemble/issues/416).
Ответ 8
Не уверен, что это полезно, но здесь пример шаблона 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"}]'
}}