通过把手传递变量


131

我目前正在express.js应用程序中处理handlebars.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>

或者。

我知道,在渲染模板之前,我能够定义所需的所有数据。但是我需要一种像刚才解释的方法。有没有办法?

Answers:


214

车把零件有第二个参数,它成为零件的上下文:

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


5
目前尚不清楚这将如何应用于您的方案?您能否写下解决方案-请在您的情况下应用它?谢谢!
服务器员

12
@Yehuda Katz而不是传递this,可以在您自己的上下文中传递。例如,定义要传入的其他数据,例如{new_variable: some_data}
Tri Nguyen

22
尽管具有传递“ this”的能力很不错,但这并不总是足够的。通常,您可能希望在同一页面上重用某个HTML片段,但是如果该部分具有ID,则注定了失败……同一ID会多次显示并变得无效。如果可以在调用局部函数时将参数传递给局部函数,以进一步自定义其内容,这将非常有用。
Xavier_Ex 2013年

2
哪个版本的把手支持此功能?我正在使用1.3.0,并且尝试通过{{> partialName {new_variable: some_data} }}
bafromca 2014年

1
@bafromca多数民众赞成在确切的问题,你不能传递任意数据,而只有一个单一的对象。因此,您可以传递此参数,也可以创建一个新属性,该属性将在控制器或视图中返回json数据。我其次认为应该可以将任意数据传递给局部数据key=value。github上有没有涉及这个的问题?
ohcibi 2014年

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

这里的关键是Handlebars助手接受一个类似Ruby的参数散列。在帮助程序代码中,它们作为函数的最后一个参数options(在其hash成员中)的一部分出现。这样,您可以接收第一个参数(部分名称),然后获取数据。

然后,您可能想Handlebars.SafeString从帮助程序中返回a 或使用“三重存储” — {{{防止其两次转义。

这是一个或多或少完整的使用方案:

<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'对象中寻找它们:{{hash.foo}}。(我是手把的新手,这花了我一段时间才能弄清楚)-谢谢,非常棒的助手!
克劳迪奥·布雷德费尔特

请注意,这要求您在使用帮助器之前预先编译您的局部文件。我在node.js中使用了Handlebars,发现情况并非总是如此(部分是按需编译的)。我必须添加一个简单的帮助程序,以在部分加载后预编译部分,这样效果很好!
2013年

@Dan有机会分享该助手吗?:)
Tom

1
@汤姆,这(无法弄清楚如何将它很好地格式化,不好意思): 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最好将其添加为自己的答案。
Alex


9

如果您只想在部分内容中使用其他上下文,则可接受的答案非常有用。但是,它不允许您引用任何父上下文。要传递多个参数,您需要编写自己的帮助器。这是把手的工作帮手2.0.0(其他答案适用于version <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上尝试过该版本,并且可以完美地工作。
ChristopherLörken15年

此“搜索”在哪里寻找名为“ ...”的部分?
kemagezien

8

听起来您想做这样的事情:

{{> person {another: 'attribute'} }}

Yehuda已经为您提供了一种方法:

{{> person this}}

但是要澄清一下:

要为您的部分数据提供自己的数据,只需在现有模型中为其提供自己的模型,如下所示:

{{> person this.childContext}}

换句话说,如果这是您要提供给模板的模型:

var model = {
    some : 'attribute'
}

然后添加一个新的对象给部分:

var model = {
    some : 'attribute',
    childContext : {
        'another' : 'attribute' // this goes to the child partial
    }
}

childContext就像Yehuda所说的那样成为部分上下文的上下文-在那儿,它只看到该字段another,但看不到(或关心该字段some)。如果您id在顶层模型中,并id在childContext中再次重复,那将很好用,因为Partial只看到其中的内容childContext



1

不确定是否有帮助,但这是一个Handlebars模板的示例,其中动态参数传递给了嵌入式RadioButtons部分,并且客户端(浏览器)呈现了容器中的单选按钮。

对于我来说,它是使用服务器上的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"}]' 
}}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.