Melewati variabel melalui setang sebagian


131

Saat ini saya sedang berurusan dengan setang.js dalam aplikasi express.js. Untuk menjaga hal-hal modular, saya membagi semua templat saya menjadi parsial.

Masalah saya : Saya tidak dapat menemukan cara untuk mengirimkan variabel melalui doa parsial. Katakanlah saya memiliki sebagian yang terlihat seperti ini:

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

Mari kita asumsikan saya mendaftarkan parsial ini dengan nama 'myPartial'. Di template lain saya kemudian bisa mengatakan sesuatu seperti:

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

Ini berfungsi dengan baik, sebagian akan diberikan seperti yang diharapkan dan saya adalah pengembang yang bahagia. Tapi yang saya butuhkan sekarang adalah cara untuk mengirimkan variabel yang berbeda melalui permohonan ini, untuk memeriksa sebagian misalnya, apakah judul diberikan atau tidak. Sesuatu seperti:

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

Dan invokasinya akan terlihat seperti ini:

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

atau lebih.

Saya tahu, bahwa saya dapat mendefinisikan semua data yang saya butuhkan, sebelum saya membuat templat. Tetapi saya perlu cara untuk melakukannya seperti yang baru saja dijelaskan. Apakah ada cara yang memungkinkan?

Jawaban:


214

Parsial setang mengambil parameter kedua yang menjadi konteks untuk parsial:

{{> person this}}

Di versi v2.0.0 alfa dan yang lebih baru, Anda juga bisa melewatkan hash parameter bernama:

{{> person headline='Headline'}}

Anda dapat melihat tes untuk skenario ini: https://github.com/wycats/handlebars.js/blob/ce74c36118ffed1779889d97e6a2a1028ae61510/spec/qunit_spec.js#L456-L462 https://github.com/wycats/hand.js gumpalan / e290ec24f131f89ddf2c6aeb707a4884d41c3c6d / spec / partials.js # L26-L32


5
Tidak segera jelas bagaimana ini akan berlaku untuk skenario Anda? Bisakah Anda menuliskan solusinya - menerapkannya dalam kasus Anda? Terima kasih!
serverman

12
@Yehuda Katz alih-alih lewat this, bisakah Anda memberikan konteks Anda sendiri. Misalnya, tentukan data tambahan untuk dilewati, seperti {new_variable: some_data}?
Tri Nguyen

22
Meskipun memiliki kemampuan untuk melewati "ini" itu baik, itu tidak selalu cukup. Seringkali Anda ingin menggunakan kembali sebagian html tertentu pada halaman yang sama, tetapi Anda akan ditakdirkan jika parsial memiliki ID ... ID yang sama akan muncul lebih dari satu kali dan menjadi tidak valid. Ini akan sangat berguna jika Anda bisa memberikan argumen kepada sebagian ketika memintanya, untuk lebih lanjut menyesuaikan kontennya.
Xavier_Ex

2
Versi Gagang mana yang mendukung ini? Saya menggunakan 1.3.0 dan memiliki kesalahan kompilasi ketika mencoba untuk mengirim json via{{> partialName {new_variable: some_data} }}
bafromca

1
@ bafromca itulah masalah persisnya Anda tidak bisa melewatkan data arbitrer tetapi hanya satu objek tunggal. Jadi Anda melewati ini atau Anda membuat properti baru yang mengembalikan data json Anda di controller atau tampilan. Saya kedua bahwa itu harus mungkin untuk melewati data sewenang-wenang untuk sebagian dalam bentuk key=value. Apakah ada masalah yang membahas hal ini di github?
ohcibi

18

Untuk jaga-jaga, inilah yang saya lakukan untuk mendapatkan argumen parsial, semacam. Saya telah membuat pembantu kecil yang mengambil nama parsial dan parameter hash yang akan diteruskan ke parsial:

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

Kuncinya di sini adalah bahwa pembantunya Setang menerima hash argumen seperti Ruby . Dalam kode helper, mereka datang sebagai bagian dari argumen terakhir fungsi options- - di dalamnyahash anggota. Dengan cara ini Anda bisa menerima argumen pertama — nama sebagian — dan mendapatkan data setelah itu.

Kemudian, Anda mungkin ingin mengembalikan Handlebars.SafeStringdari helper atau menggunakan "triple-stash" -{{{ - untuk mencegahnya melarikan diri ganda.

Berikut ini adalah skenario penggunaan yang kurang lebih lengkap:

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

Semoga ini bisa membantu ... seseorang. :)


15

Ini sangat mungkin jika Anda menulis pembantu Anda sendiri. Kami menggunakan $pembantu khusus untuk menyelesaikan jenis interaksi ini (dan banyak lagi):

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

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
Untuk memiliki akses ke argumen yang diteruskan, Anda perlu mencarinya ke dalam objek 'hash': {{hash.foo}}. (Saya baru menggunakan setang dan ini membutuhkan waktu beberapa saat untuk saya mengerti) - Terima kasih, penolong hebat!
Claudio Bredfeldt

Catatan, ini mengharuskan Anda untuk membuat sebagian parsial Anda dikompilasi sebelum menggunakan helper. Saya menggunakan Setang di node.js, dan menemukan bahwa ini tidak selalu terjadi (parsial dikompilasi berdasarkan permintaan). Saya harus menambahkan pembantu sederhana untuk pra-kompilasi parsial setelah mereka dimuat, maka ini bekerja hebat!
Dan

@Apakah Anda punya kesempatan untuk membagikan bantuan itu? :)
Tom

1
@ Tom, Ini dia (tidak tahu cara memformatnya dengan baik, maaf): 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 Mungkin lebih baik menambahkannya sebagai jawaban sendiri.
alex


9

Jawaban yang diterima berfungsi dengan baik jika Anda hanya ingin menggunakan konteks yang berbeda di sebagian Anda. Namun, itu tidak membiarkan Anda referensi salah satu konteks induk. Untuk menyampaikan banyak argumen, Anda harus menulis pembantu Anda sendiri. Berikut ini adalah penolong yang berfungsi untuk Setang 2.0.0(jawaban lain berfungsi untuk versi <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) );
});

Kemudian di templat Anda, Anda dapat melakukan sesuatu seperti:

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

Dan sebagian Anda akan dapat mengakses nilai-nilai itu sebagai konteks seperti:

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

Saya sudah mencoba versi ini dengan Handlebars 1.0.0 dan berfungsi dengan sempurna.
Christopher Lörken

di mana 'pencarian' ini untuk sebagian bernama '...'?
kemagezien

8

Kedengarannya Anda ingin melakukan sesuatu seperti ini:

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

Yehuda sudah memberi Anda cara untuk melakukan itu:

{{> person this}}

Tetapi untuk memperjelas:

Untuk memberikan sebagian data Anda sendiri, berikan saja modelnya sendiri di dalam model yang ada, seperti:

{{> person this.childContext}}

Dengan kata lain, jika ini adalah model yang Anda berikan ke template Anda:

var model = {
    some : 'attribute'
}

Kemudian tambahkan objek baru untuk diberikan kepada parsial:

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

childContextmenjadi konteks parsial seperti kata Yehuda - dalam hal itu, ia hanya melihat bidang another, tetapi tidak melihat (atau peduli dengan bidang some). Jika Anda memiliki idmodel tingkat atas, dan ulangi idlagi di childContext, itu akan berfungsi dengan baik karena sebagian hanya melihat apa yang ada di dalamnya childContext.



1

Tidak yakin apakah ini membantu, tetapi inilah contoh templat Templat dengan parameter dinamis yang diteruskan ke parsial RadioButtons inline dan klien (peramban) merender tombol radio dalam wadah.

Untuk penggunaan saya ini diberikan dengan Setang di server dan memungkinkan klien menyelesaikannya. Dengannya alat formulir dapat menyediakan data sebaris di dalam Setang tanpa bantuan.

Catatan: Contoh ini membutuhkan 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"}]' 
}}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.