การส่งผ่านตัวแปรผ่านแฮนด์บาร์บางส่วน


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 alpha และใหม่กว่าคุณสามารถส่งแฮชของพารามิเตอร์ที่มีชื่อ:

{{> person headline='Headline'}}

คุณสามารถดูการทดสอบสำหรับสถานการณ์เหล่านี้ได้ที่https://github.com/wycats/handlebars.js/blob/ce74c36118ffed1779889d97e6a2a1028ae61510/spec/qunit_spec.js#L456-L462 https://github.com/wycats/handlebars.js/ หยด / e290ec24f131f89ddf2c6aeb707a4884d41c3c6d / ข้อมูลจำเพาะ / partials.js # L26-L32


5
ยังไม่ชัดเจนในทันทีว่าสิ่งนี้จะนำไปใช้กับสถานการณ์ของคุณอย่างไร? คุณช่วยเขียนวิธีแก้ปัญหา - นำไปใช้ในกรณีของคุณได้ไหม ขอบคุณ!
เซิร์ฟเวอร์แมน

12
@Yehuda Katz แทนที่จะผ่านthisคุณสามารถส่งผ่านไปในบริบทของคุณเองได้ไหม ตัวอย่างเช่นกำหนดข้อมูลเพิ่มเติมที่จะส่งผ่านเช่น{new_variable: some_data}?
Tri Nguyen

22
แม้ว่าการมีความสามารถใน "สิ่งนี้" จะดี แต่ก็ยังไม่เพียงพอเสมอไป บ่อยครั้งที่คุณต้องการใช้ html บางส่วนซ้ำในหน้าเดียวกัน แต่คุณจะถึงวาระหากบางส่วนมี ID ... ID เดียวกันจะแสดงมากกว่าหนึ่งครั้งและกลายเป็นไม่ถูกต้อง จะมีประโยชน์อย่างยิ่งหากคุณสามารถส่งอาร์กิวเมนต์ไปยังบางส่วนเมื่อเรียกใช้เพื่อปรับแต่งเนื้อหาเพิ่มเติม
Xavier_Ex

2
Handlebars รุ่นใดที่รองรับสิ่งนี้ ฉันใช้ 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);
});

สิ่งสำคัญที่นี่คือ ผู้ช่วยเหลือ Handlebars ยอมรับทับทิมเหมือนกัญชาของการขัดแย้ง ในรหัสผู้ช่วยเหลือจะเป็นส่วนหนึ่งของอาร์กิวเมนต์สุดท้ายของฟังก์ชันoptions- - ในhashสมาชิก ด้วยวิธีนี้คุณจะได้รับอาร์กิวเมนต์แรก - ชื่อบางส่วน - และรับข้อมูลหลังจากนั้น

จากนั้นคุณอาจต้องการส่งคืน a 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>

หวังว่านี่จะช่วย…ใครบางคน :)


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}} (ฉันใหม่กับแฮนด์บาร์และใช้เวลาพอสมควรในการคิดออก) - ขอบคุณผู้ช่วยที่ยอดเยี่ยม!
Claudio Bredfeldt

หมายเหตุสิ่งนี้กำหนดให้คุณต้องรวบรวมบางส่วนไว้ล่วงหน้าก่อนที่จะใช้ตัวช่วย ฉันใช้ Handlebars ใน node.js และพบว่ามันไม่ได้เป็นเช่นนั้นเสมอไป (บางส่วนรวบรวมตามความต้องการ) ฉันต้องเพิ่มตัวช่วยง่ายๆในการคอมไพล์บางส่วนล่วงหน้าหลังจากโหลดแล้วมันก็ใช้งานได้ดี!
แดน

@ คุณมีโอกาสที่จะแบ่งปันผู้ช่วยคนนั้นได้หรือไม่? :)
ทอม

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]); } }; }
แดน

@ แดนน่าจะดีกว่าที่จะเพิ่มเป็นคำตอบของมันเอง
alex

14

นอกจากนี้ยังสามารถทำได้ในแฮนด์บาร์รุ่นใหม่ ๆ โดยใช้key=valueสัญกรณ์:

 {{> mypartial foo='bar' }}

อนุญาตให้คุณส่งผ่านค่าเฉพาะไปยังบริบทบางส่วนของคุณ

การอ้างอิง: บริบทที่แตกต่างกันสำหรับบางส่วน # 182


1
สามารถใช้ได้ตั้งแต่เวอร์ชัน v2.0.0 alpha
Kevin Borders

9

คำตอบที่ยอมรับจะใช้ได้ผลดีหากคุณต้องการใช้บริบทอื่นในบางส่วนของคุณ อย่างไรก็ตามไม่อนุญาตให้คุณอ้างอิงบริบทหลักใด ๆ ในการส่งผ่านข้อโต้แย้งต่างๆคุณต้องเขียนผู้ช่วยของคุณเอง นี่คือตัวช่วยที่ใช้งานได้สำหรับ 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>

ฉันได้ลองรุ่นนี้กับ Handlebars 1.0.0 แล้วและใช้งานได้อย่างไม่มีที่ติ
Christopher Lörken

สิ่งนี้จะ 'ค้นหา' สำหรับบางส่วนชื่อ '... ' ที่ไหน
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 สิ่งนั้นจะใช้ได้ดีเพราะบางส่วนจะเห็นเฉพาะสิ่งที่อยู่ภายในchildContextเท่านั้น



1

ไม่แน่ใจว่าจะมีประโยชน์หรือไม่ แต่นี่คือตัวอย่างของเทมเพลต 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"}]' 
}}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.