Передача змінних через рульове часткове


131

Зараз я маю справу з 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>

або так.

Я знаю, що я можу визначити всі потрібні мені дані, перш ніж надати шаблон. Але мені потрібен спосіб це зробити, як щойно пояснено. Чи можливий спосіб?

Відповіді:


214

Партії рульового колеса приймають другий параметр, який стає контекстом для часткового:

{{> person this}}

У версіях v2.0.0 альфа та пізніших версіях ви також можете передавати хеш з названими параметрами:

{{> 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


5
Не відразу зрозуміло, як це стосуватиметься вашого сценарію? Чи можете ви записати рішення - застосовуючи його у вашому випадку, будь ласка? Дякую!
сервер

12
@Yehuda Katz замість того this, щоб пройти, ви могли б пройти у власному контексті. Наприклад, визначте додаткові дані для передачі, наприклад {new_variable: some_data}?
Tri Nguyen

22
Хоча мати можливість пройти «це» приємно, цього не завжди достатньо. Часто ви хочете повторно використовувати певний фрагмент HTML потенційно на одній сторінці, але ви приречені, якщо частковий має ідентифікатори ... той самий ідентифікатор з’явиться не один раз і стане недійсним. Було б надзвичайно корисно, якщо ви можете передавати аргументи приватним особам під час виклику, щоб додатково налаштувати його вміст.
Xavier_Ex

2
Яка версія рулі підтримує це? Я використовую 1.3.0, і він має помилку компіляції при спробі передати json через{{> partialName {new_variable: some_data} }}
bafromca

1
@bafromca ось точна проблема, ви не можете передавати довільні дані, а лише один єдиний об'єкт. Таким чином, ви або передаєте це, або створюєте нову властивість, яка повертає ваші json-дані в контролер або в представлення. По-друге, що має бути можливість передавати довільні дані до часткових у вигляді key=value. Чи є питання, що висвітлює це в github?
ohcibi

18

Про всяк випадок, ось що я зробив, щоб отримати часткові аргументи. Я створив маленьку помічницю, яка має часткове ім’я та хеш параметрів, які будуть передані часткові:

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);
});

Тут головне, що помічники рукоятки приймають хеш аргументів, схожий на 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>

Сподіваюся, це допомагає ... комусь. :)


15

Це дуже можливо, якщо ви напишете власного помічника. Ми використовуємо спеціальний $помічник для здійснення такого типу взаємодії (і багато іншого):

/*///////////////////////

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) );
});

1
Щоб мати доступ до переданих аргументів, потрібно шукати їх у об’єкті 'хеш': {{hash.foo}}. (Я новачок з кермом, і це знадобило мені час, щоб розібратися) - Дякую, чудовий помічник!
Клаудіо Бредфельдт

Зауважте, для цього потрібно попередньо скласти свої партії перед використанням помічника. Я використовував ручки в node.js, і виявив, що це не завжди так (партії складалися на вимогу). Мені довелося додати простого помічника, щоб попередньо скласти партії після їх завантаження, тоді це спрацювало чудово!
День

@ Чи є якийсь шанс ви могли поділитися цим помічником? :)
Том

1
@Tom, ось це (не можу зрозуміти, як це добре відформатувати, вибачте): hbs.registerPartials(path.join(__dirname, '/views/partials'), function() { utils.precompileHandlebarsPartials(hbs); }); // Pre compile the partials precompileHandlebarsPartials : function(hbs) { var partials = hbs.handlebars.partials; for (var partial in partials) { if (typeof partials[partial] === 'string') { partials[partial] = hbs.handlebars.compile(partials[partial]); } }; }
Dan

@Dan Напевно, краще додати це як власну відповідь.
alex

14

Це також можна зробити в більш пізніх версіях рульових інструментів, використовуючи key=valueпозначення:

 {{> mypartial foo='bar' }}

Дозволяє вам передавати конкретні значення вашому частковому контексту.

Довідка: інший контекст для часткової №182


1
Це доступно починаючи з версії v2.0.0 альфа
Кевін Бордс

9

Прийнята відповідь чудово працює, якщо ви просто хочете використовувати інший контекст у своїй частковій справі. Однак це не дозволяє вам посилатися на жоден з батьківських контекстів. Щоб передати кілька аргументів, потрібно написати власного помічника. Ось робочий помічник у руль 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>

Я спробував цю версію з Handlebars 1.0.0, і вона працювала бездоганно.
Крістофер Леркен

звідки цей "пошук" часткової назви "..."?
kemagezien

8

Здається, ви хочете зробити щось подібне:

{{> 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.



1

Не впевнений, чи це корисно, але ось приклад шаблону рульових колекцій з динамічними параметрами, переданими в вбудовану частину RadioButtons, і клієнтом (браузером), що передає радіо кнопки в контейнері.

Для мого використання він надається з ручками на сервері і дозволяє клієнту закінчити його. З його допомогою інструмент форм може надавати вбудовані дані в руль без помічників.

Примітка. Цей приклад вимагає 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"}]' 
}}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.