Variablen teilweise über den Lenker übergeben


131

Ich beschäftige mich derzeit mit handlebars.js in einer express.js-Anwendung. Um die Dinge modular zu halten, habe ich alle meine Vorlagen in Teilvorlagen aufgeteilt.

Mein Problem : Ich konnte keinen Weg finden, Variablen durch einen Teilaufruf zu übergeben. Nehmen wir an, ich habe einen Teil, der so aussieht:

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

Nehmen wir an, ich habe diesen Teil mit dem Namen 'myPartial' registriert. In einer anderen Vorlage kann ich dann so etwas sagen wie:

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

Dies funktioniert gut, der Teil wird wie erwartet gerendert und ich bin ein glücklicher Entwickler. Was ich jetzt brauche, ist eine Möglichkeit, verschiedene Variablen durch diesen Aufruf zu übergeben, um beispielsweise innerhalb eines Teils zu überprüfen, ob eine Überschrift angegeben ist oder nicht. Etwas wie:

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

Und die Anrufung sollte ungefähr so ​​aussehen:

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

oder so.

Ich weiß, dass ich alle benötigten Daten definieren kann, bevor ich eine Vorlage rendere. Aber ich brauche einen Weg, es so zu machen, wie es gerade erklärt wurde. Gibt es einen möglichen Weg?

Antworten:


214

Lenkerpartials verwenden einen zweiten Parameter, der zum Kontext für das Partial wird:

{{> person this}}

In Versionen v2.0.0 alpha und höher können Sie auch einen Hash benannter Parameter übergeben:

{{> person headline='Headline'}}

Sie können die Tests für diese Szenarien anzeigen : https://github.com/wycats/handlebars.js/blob/ce74c36118ffed1779889d97e6a2a1028ae61510/spec/qunit_spec.js#L456-L462 https://github.com/wycats/handle blob / e290ec24f131f89ddf2c6aeb707a4884d41c3c6d / spec / teilweise.js # L26-L32


5
Es ist nicht sofort klar, wie dies auf Ihr Szenario zutreffen würde. Könnten Sie die Lösung aufschreiben - wenden Sie sie bitte in Ihrem Fall an? Vielen Dank!
Serverman

12
@Yehuda Katz anstatt zu übergeben this, könnten Sie in Ihrem eigenen Kontext übergeben. Definieren Sie beispielsweise zusätzliche Daten, die übergeben werden sollen, z {new_variable: some_data}.
Tri Nguyen

22
Die Fähigkeit, "dies" weiterzugeben, ist zwar schön, aber nicht immer genug. Oft möchten Sie ein bestimmtes Stück HTML möglicherweise auf derselben Seite wiederverwenden, aber Sie sind zum Scheitern verurteilt, wenn der Teil IDs hat ... dieselbe ID wird mehr als einmal angezeigt und wird ungültig. Es wäre äußerst nützlich, wenn Sie beim Aufrufen Argumente an Partials übergeben könnten, um den Inhalt weiter anzupassen.
Xavier_Ex

2
Welche Lenkerversion unterstützt dies? Ich benutze 1.3.0 und es hat einen Kompilierungsfehler beim Versuch, json über{{> partialName {new_variable: some_data} }}
bafromca

1
@bafromca das ist genau das Problem, Sie können keine beliebigen Daten übergeben, sondern nur ein einziges Objekt. Sie übergeben dies entweder oder Sie erstellen eine neue Eigenschaft, die Ihre JSON-Daten im Controller oder in der Ansicht zurückgibt. Ich zweitens, dass es möglich sein sollte, beliebige Daten in Form von an partielle Daten weiterzugeben key=value. Gibt es ein Problem, das dies in Github abdeckt?
Ohcibi

18

Nur für den Fall, hier ist, was ich getan habe, um teilweise Argumente zu bekommen, irgendwie. Ich habe einen kleinen Helfer erstellt, der einen Teilnamen und einen Hash von Parametern verwendet, die an den Teil übergeben werden:

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

Das Wichtigste dabei ist, dass Lenkerhelfer einen Ruby-ähnlichen Hash von Argumenten akzeptieren . Im Hilfecode sind sie Teil des letzten Arguments der Funktion options- - in ihrem hashMitglied. Auf diese Weise können Sie das erste Argument - den Teilnamen - erhalten und die Daten danach abrufen.

Dann möchten Sie wahrscheinlich ein Handlebars.SafeStringvom Helfer zurückgeben oder "Triple-Stash" verwenden {{{, um zu verhindern, dass es doppelt entweicht.

Hier ist ein mehr oder weniger vollständiges Nutzungsszenario:

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

Hoffe das hilft ... jemandem. :) :)


15

Dies ist sehr gut möglich, wenn Sie Ihren eigenen Helfer schreiben. Wir verwenden einen benutzerdefinierten $Helfer, um diese Art der Interaktion (und mehr) durchzuführen:

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

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
Um auf die übergebenen Argumente zugreifen zu können, müssen Sie sie im 'Hash'-Objekt suchen: {{hash.foo}}. (Ich bin neu im Lenker und es hat eine Weile gedauert, bis ich es herausgefunden habe.) - Danke, großartiger Helfer!
Claudio Bredfeldt

Beachten Sie, dass Sie dazu Ihre Partials vorkompilieren müssen, bevor Sie den Helfer verwenden können. Ich verwende Lenker in node.js und habe festgestellt, dass dies nicht immer der Fall ist (die Partials wurden bei Bedarf kompiliert). Ich musste einen einfachen Helfer hinzufügen, um Partials nach dem Laden vorkompilieren zu können, dann funktionierte das großartig!
Dan

@ Hast du eine Chance, diesen Helfer zu teilen? :)
Tom

1
@ Tom, hier ist es (kann nicht herausfinden, wie man es schön formatiert, sorry): 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 Wahrscheinlich besser, es als eigene Antwort hinzuzufügen.
alex


9

Die akzeptierte Antwort funktioniert hervorragend, wenn Sie in Ihrem Teil nur einen anderen Kontext verwenden möchten. Sie können jedoch nicht auf den übergeordneten Kontext verweisen. Um mehrere Argumente zu übergeben, müssen Sie Ihren eigenen Helfer schreiben. Hier ist ein funktionierender Helfer für Lenker 2.0.0(die andere Antwort funktioniert für Versionen <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) );
});

Dann können Sie in Ihrer Vorlage Folgendes tun:

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

Und in Ihrem Teil können Sie auf diese Werte als Kontext zugreifen wie:

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

Ich habe diese Version mit Handlebars 1.0.0 ausprobiert und sie hat einwandfrei funktioniert.
Christopher Lörken

Wo sucht diese nach einem Teil mit dem Namen "..."?
Kemagezien

8

Klingt so, als ob Sie so etwas tun möchten:

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

Yehuda hat dir schon einen Weg gegeben, das zu tun:

{{> person this}}

Aber um zu verdeutlichen:

Um Ihrem Teil eigene Daten zu geben, geben Sie ihm einfach ein eigenes Modell innerhalb des vorhandenen Modells, wie folgt:

{{> person this.childContext}}

Mit anderen Worten, wenn dies das Modell ist, das Sie Ihrer Vorlage geben:

var model = {
    some : 'attribute'
}

Fügen Sie dann ein neues Objekt hinzu, das dem Teil gegeben werden soll:

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

childContextwird zum Kontext des Teils, wie Yehuda sagte - darin sieht es nur das Feld another, aber es sieht nicht (oder kümmert sich nicht um das Feld some). Wenn Sie iddas Modell der obersten Ebene hatten und ides im childContext erneut wiederholen , funktioniert dies einwandfrei, da der Teil nur sieht, was sich darin befindet childContext.



1

Ich bin mir nicht sicher, ob dies hilfreich ist, aber hier ist ein Beispiel für eine Lenkervorlage mit dynamischen Parametern, die an einen Inline-Teil von RadioButtons übergeben werden, und dem Client (Browser), der die Optionsfelder im Container rendert.

Für meine Verwendung wird es mit Lenkern auf dem Server gerendert und lässt den Client es beenden. Mit ihm kann ein Formular-Tool Inline-Daten innerhalb des Lenkers ohne Helfer bereitstellen.

Hinweis: Für dieses Beispiel ist jQuery erforderlich

{{#*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"}]' 
}}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.