Passando variabili attraverso il manubrio parziale


131

Attualmente ho a che fare con handlebars.js in un'applicazione express.js. Per mantenere le cose modulari, ho diviso tutti i miei modelli in parziali.

Il mio problema : non sono riuscito a trovare un modo per passare le variabili attraverso una chiamata parziale. Diciamo che ho un parziale che assomiglia a questo:

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

Supponiamo di aver registrato questo parziale con il nome "myPartial". In un altro modello posso quindi dire qualcosa del tipo:

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

Funziona bene, il parziale verrà reso come previsto e sono uno sviluppatore felice. Ma ciò di cui ho bisogno ora è un modo per passare diverse variabili attraverso questa invocazione, per verificare in un parziale, ad esempio, se viene dato un titolo o meno. Qualcosa di simile a:

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

E l'invocazione dovrebbe essere simile a questa:

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

o così.

So che sono in grado di definire tutti i dati di cui ho bisogno, prima di renderizzare un modello. Ma ho bisogno di un modo per farlo come appena spiegato. C'è un modo possibile?

Risposte:


214

I parziali del manubrio accettano un secondo parametro che diventa il contesto del parziale:

{{> person this}}

Nelle versioni v2.0.0 alpha e successive, puoi anche passare un hash di parametri nominati:

{{> person headline='Headline'}}

Puoi vedere i test per questi scenari: 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
Non è immediatamente chiaro come ciò si applicherebbe al tuo scenario? Potresti scrivere la soluzione - applicandola nel tuo caso, per favore? Grazie!
serverman

12
@Yehuda Katz invece di passare this, potresti passare nel tuo contesto. Ad esempio, definire dati aggiuntivi da trasmettere, come {new_variable: some_data}?
Tri Nguyen,

22
Anche se avere la possibilità di passare "questo" è bello, non è sempre abbastanza. Spesso vuoi riutilizzare un certo pezzo di html potenzialmente sulla stessa pagina, ma sei condannato se il parziale ha ID ... lo stesso ID verrà mostrato più di una volta e non sarà più valido. Sarebbe estremamente utile se puoi invocare argomenti ai parziali quando lo invochi, per personalizzare ulteriormente il suo contenuto.
Xavier_Ex

2
Quale versione di Handlebars supporta questo? Sto usando 1.3.0 e ha un errore di compilazione quando {{> partialName {new_variable: some_data} }}
provo

1
@bafromca è il problema esatto che non puoi trasmettere dati arbitrari ma solo un singolo oggetto. Quindi o passi questo o crei una nuova proprietà che restituisce i tuoi dati json nel controller o nella vista. In secondo luogo, dovrebbe essere possibile trasmettere dati arbitrari a parziali sotto forma di key=value. C'è qualche problema a riguardo in Github?
ohcibi,

18

Per ogni evenienza, ecco cosa ho fatto per ottenere argomenti parziali, in un certo senso. Ho creato un piccolo aiuto che prende un nome parziale e un hash di parametri che verranno passati al parziale:

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

La cosa chiave qui è che gli aiutanti di Manubrio accettano un hash di argomenti tipo Ruby . Nel codice helper rientrano nell'ultimo argomento della funzione options- - nel suo hashmembro. In questo modo è possibile ricevere il primo argomento, il nome parziale, e ottenere successivamente i dati.

Quindi, probabilmente si desidera restituire a Handlebars.SafeStringdall'helper o utilizzare "triple-stash" - {{{- per evitare che fuoriesca doppiamente.

Ecco uno scenario di utilizzo più o meno completo:

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

Spero che questo aiuti ... qualcuno. :)


15

Questo è molto possibile se scrivi il tuo aiutante. Stiamo usando un $aiuto personalizzato per realizzare questo tipo di interazione (e altro):

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

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
Per accedere agli argomenti passati, è necessario cercarli nell'oggetto 'hash': {{hash.foo}}. (Sono nuovo con il manubrio e mi ci è voluto un po 'di tempo per capire) - Grazie, grande aiuto!
Claudio Bredfeldt,

Nota, questo richiede che i tuoi parziali siano precompilati prima di usare l'helper. Sto usando il manubrio in node.js e ho scoperto che non è sempre stato così (i parziali sono stati compilati su richiesta). Ho dovuto aggiungere un semplice aiuto per pre-compilare i parziali dopo che sono stati caricati, quindi ha funzionato alla grande!
Dan

Hai qualche possibilità di condividere quell'aiuto? :)
Tom,

1
@Tom, Eccolo (non riesco a capire come formattarlo bene, mi dispiace): 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 Probabilmente è meglio aggiungerlo come propria risposta.
alex

14

Questo può essere fatto anche nelle versioni successive del manubrio usando la key=valuenotazione:

 {{> mypartial foo='bar' }}

Permettendoti di passare valori specifici al tuo contesto parziale.

Riferimento: contesto diverso per il parziale # 182


1
Questo è disponibile a partire dalla versione v2.0.0 alpha
Kevin Borders,

9

La risposta accettata funziona benissimo se vuoi solo usare un contesto diverso nel tuo parziale. Tuttavia, non consente di fare riferimento a nessuno dei contesti principali. Per passare più argomenti, è necessario scrivere il proprio aiuto. Ecco un aiuto funzionante per il manubrio 2.0.0(l'altra risposta funziona per le versioni <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) );
});

Quindi, nel tuo modello, puoi fare qualcosa del tipo:

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

E nel tuo parziale, sarai in grado di accedere a quei valori come contesto come:

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

Ho provato questa versione con Handlebars 1.0.0 e ha funzionato perfettamente.
Christopher Lörken,

da dove viene questa "ricerca" di un nome parziale "..."?
kemagezien,

8

Sembra che tu voglia fare qualcosa del genere:

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

Yehuda ti ha già dato un modo per farlo:

{{> person this}}

Ma per chiarire:

Per dare ai tuoi dati parziali i tuoi dati, devi solo dargli un modello all'interno del modello esistente, in questo modo:

{{> person this.childContext}}

In altre parole, se questo è il modello che stai dando al tuo modello:

var model = {
    some : 'attribute'
}

Quindi aggiungere un nuovo oggetto da assegnare al parziale:

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

childContextdiventa il contesto del parziale come diceva Yehuda - in questo vede solo il campo another, ma non vede (o si preoccupa del campo some). Se avevi idnel modello di livello superiore e ripeti di idnuovo in ChildContext, funzionerà bene poiché il parziale vede solo ciò che c'è dentro childContext.



1

Non sono sicuro che ciò sia utile, ma ecco un esempio di modello di manubrio con parametri dinamici passati a un RadioButtons inline parziale e al client (browser) che esegue il rendering dei pulsanti di opzione nel contenitore.

Per il mio uso è reso con i manubri sul server e consente al client di completarlo. Con esso uno strumento di moduli può fornire dati incorporati all'interno del manubrio senza aiutanti.

Nota: questo esempio richiede 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"}]' 
}}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.