Truyền biến qua tay lái một phần


131

Tôi hiện đang làm việc với handlebars.js trong một ứng dụng express.js. Để giữ mọi thứ theo mô-đun, tôi chia tất cả các mẫu của mình thành từng phần.

Vấn đề của tôi : Tôi không thể tìm ra cách chuyển các biến thông qua một lệnh gọi một phần. Hãy nói rằng tôi có một phần trông như thế này:

<div id=myPartial>
    <h1>Headline<h1>
    <p>Lorem ipsum</p>
</div>

Giả sử tôi đã đăng ký một phần này với tên 'myPartial'. Trong một mẫu khác, sau đó tôi có thể nói một cái gì đó như:

<section>
    {{> myPartial}}
</section>

Điều này hoạt động tốt, một phần sẽ được hiển thị như mong đợi và tôi là một nhà phát triển hạnh phúc. Nhưng những gì tôi cần bây giờ, là một cách để vượt qua các biến khác nhau thông qua lời mời này, để kiểm tra trong một phần chẳng hạn, nếu một tiêu đề được đưa ra hay không. Cái gì đó như:

<div id=myPartial>
    {{#if headline}}
    <h1>{{headline}}</h1>
    {{/if}}
    <p>Lorem Ipsum</p>
</div>

Và lời mời sẽ trông giống như thế này:

<section>
    {{> myPartial|'headline':'Headline'}}
</section>

hoặc là.

Tôi biết rằng tôi có thể xác định tất cả dữ liệu tôi cần, trước khi tôi kết xuất một mẫu. Nhưng tôi cần một cách để làm điều đó như vừa giải thích. Có một cách có thể?

Câu trả lời:


214

Các phần của tay lái lấy tham số thứ hai trở thành bối cảnh cho một phần:

{{> person this}}

Trong phiên bản v2.0.0 alpha trở lên, bạn cũng có thể vượt qua hàm băm của các tham số được đặt tên:

{{> person headline='Headline'}}

Bạn có thể xem các bài kiểm tra cho các kịch bản này: https://github.com/wycats/handlebars.js/blob/ce74c36118ffed1779889d97e6a2a1028ae61510/spec/qunit_spec.js#L456-L462 https : // github blob / e290ec24f131f89ddf2c6aeb707a4884d41c3c6d / spec / partials.js # L26-L32


5
Vẫn chưa rõ làm thế nào điều này sẽ áp dụng cho kịch bản của bạn? Bạn có thể viết ra giải pháp - áp dụng nó trong trường hợp của bạn không? Cảm ơn!
serverman

12
@Yehuda Katz thay vì đi vào this, bạn có thể vượt qua trong bối cảnh của riêng bạn. Ví dụ: xác định dữ liệu bổ sung để truyền vào, chẳng hạn như {new_variable: some_data}?
Tri Nguyễn

22
Mặc dù có khả năng vượt qua "điều này" là tốt, nhưng điều đó không phải lúc nào cũng đủ. Thường thì bạn muốn sử dụng lại một đoạn html nhất định có khả năng trên cùng một trang, nhưng bạn sẽ phải chịu số phận nếu một phần có ID ... cùng một ID sẽ xuất hiện nhiều lần và trở nên không hợp lệ. Sẽ cực kỳ hữu ích nếu bạn có thể chuyển các đối số sang các phần khi gọi nó, để tùy chỉnh thêm nội dung của nó.
Xavier_Ex

2
Phiên bản nào của Tay cầm hỗ trợ này? Tôi đang sử dụng 1.3.0 và nó có lỗi biên dịch khi cố gắng chuyển json qua{{> partialName {new_variable: some_data} }}
bafromca

1
@bafromca đó là vấn đề chính xác, bạn không thể truyền dữ liệu tùy ý mà chỉ có một đối tượng. Vì vậy, bạn hoặc vượt qua điều này hoặc bạn tạo một thuộc tính mới trả về dữ liệu json của bạn trong bộ điều khiển hoặc dạng xem. Tôi thứ hai rằng nó có thể truyền dữ liệu tùy ý sang một phần dưới dạng key=value. Có bất kỳ vấn đề bao gồm điều này trong github?
ohcibi

18

Chỉ trong trường hợp, đây là những gì tôi đã làm để có được một phần đối số, loại. Tôi đã tạo một trình trợ giúp nhỏ có tên một phần và hàm băm của các tham số sẽ được truyền cho một phần:

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

Điều quan trọng ở đây là người trợ giúp Tay lái chấp nhận hàm băm đối số giống như Ruby . Trong mã trình trợ giúp, chúng là một phần của đối số cuối cùng của hàm options- trong hashthành viên của nó . Bằng cách này, bạn có thể nhận được đối số đầu tiên, tên một phần tên và nhận dữ liệu sau đó.

Sau đó, bạn có thể muốn trả lại một Handlebars.SafeStringtừ người trợ giúp hoặc sử dụng bộ ba “stash - {{{- để ngăn nó thoát gấp đôi.

Đây là một kịch bản sử dụng ít nhiều hoàn thành:

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

Hy vọng điều này sẽ giúp ích cho ai đó. :)


15

Điều này là rất có thể nếu bạn viết người trợ giúp của riêng bạn. Chúng tôi đang sử dụng một trình $trợ giúp tùy chỉnh để thực hiện loại tương tác này (và hơn thế nữa):

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

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
Để có quyền truy cập vào các đối số đã truyền, bạn cần tìm chúng vào đối tượng 'hash': {{hash.foo}}. (Tôi mới sử dụng tay lái và điều này khiến tôi mất một lúc để tìm hiểu) - Cảm ơn, người trợ giúp tuyệt vời!
Claudio Bredfeldt

Lưu ý, điều này đòi hỏi bạn phải có các phần của bạn được biên dịch trước khi sử dụng trình trợ giúp. Tôi đang sử dụng Tay cầm trong node.js và thấy rằng điều này không phải luôn luôn như vậy (các phần được biên dịch theo yêu cầu). Tôi đã phải thêm một trình trợ giúp đơn giản để biên dịch trước các phần sau khi chúng được tải, sau đó điều này hoạt động rất tốt!
Dan

@ Bạn có thể chia sẻ người trợ giúp đó không? :)
Tom

1
@Tom, đây là (không thể tìm ra cách định dạng độc đáo, xin lỗi): 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 Có lẽ tốt hơn để thêm nó như là câu trả lời của riêng mình.
alex

14

Điều này cũng có thể được thực hiện trong các phiên bản sau của tay lái bằng cách sử dụng key=valueký hiệu:

 {{> mypartial foo='bar' }}

Cho phép bạn chuyển các giá trị cụ thể vào bối cảnh một phần của bạn.

Tham khảo: Bối cảnh khác nhau cho một phần # 182


1
Điều này có sẵn bắt đầu trong phiên bản v2.0.0 alpha
Kevin

9

Câu trả lời được chấp nhận hoạt động tuyệt vời nếu bạn chỉ muốn sử dụng một bối cảnh khác trong một phần của bạn. Tuy nhiên, nó không cho phép bạn tham khảo bất kỳ bối cảnh cha mẹ. Để vượt qua trong nhiều đối số, bạn cần viết trình trợ giúp của riêng bạn. Đây là một trợ giúp làm việc cho Tay cầm 2.0.0(câu trả lời khác hoạt động cho các phiên bản <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) );
});

Sau đó, trong mẫu của bạn, bạn có thể làm một cái gì đó như:

{{renderPartial 'myPartialName' foo=this bar=../bar}}

Và trong phần của bạn, bạn sẽ có thể truy cập các giá trị đó dưới dạng bối cảnh như:

<div id={{bar.id}}>{{foo}}</div>

Tôi đã thử phiên bản này với Tay cầm 1.0.0 và nó hoạt động hoàn hảo.
Christopher Lörken

nơi này 'tìm kiếm' cho một phần có tên '...'?
kemagezien

8

Âm thanh như bạn muốn làm một cái gì đó như thế này:

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

Yehuda đã cho bạn một cách để làm điều đó:

{{> person this}}

Nhưng để làm rõ:

Để cung cấp cho một phần dữ liệu của riêng bạn, chỉ cần cung cấp cho mô hình của chính nó trong mô hình hiện có, như vậy:

{{> person this.childContext}}

Nói cách khác, nếu đây là mô hình bạn đang cung cấp cho mẫu của mình:

var model = {
    some : 'attribute'
}

Sau đó thêm một đối tượng mới sẽ được trao cho một phần:

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

childContexttrở thành bối cảnh của một phần như Yehuda đã nói - trong đó, nó chỉ nhìn thấy cánh đồng another, nhưng nó không nhìn thấy (hoặc quan tâm đến lĩnh vực này some). Nếu bạn đã có idtrong mô hình cấp cao nhất và lặp lại idmột lần nữa trong childContext, điều đó sẽ hoạt động tốt vì một phần chỉ nhìn thấy những gì bên trong childContext.



1

Không chắc điều này có hữu ích hay không nhưng đây là một ví dụ về mẫu Tay cầm với các tham số động được truyền cho một phần RadioButtons nội tuyến và ứng dụng khách (trình duyệt) hiển thị các nút radio trong vùng chứa.

Đối với mục đích sử dụng của tôi, nó được kết xuất với Tay cầm trên máy chủ và cho phép khách hàng hoàn thành nó. Với nó, một công cụ biểu mẫu có thể cung cấp dữ liệu nội tuyến trong Tay cầm mà không cần người trợ giúp.

Lưu ý: Ví dụ này yêu cầu 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"}]' 
}}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.