abhängig vom letzten Element im Array mithilfe der Vorlage handlebars.js

73

Ich nutze handlebars.js für meine Vorlagen-Engine und möchte nur dann eine bedingte Segmentanzeige erstellen, wenn es sich um das letzte Element im Array handelt, das im Vorlagenkonfigurationsobjekt enthalten ist.

{
  columns: [{<obj>},{<obj>},{<obj>},{<obj>},{<obj>}]
}

Ich habe bereits einen Helfer hinzugezogen, um Vergleiche zwischen Gleichheit / Größer / Kleiner als durchzuführen, und hatte Erfolg bei der Identifizierung des ursprünglichen Elements auf diese Weise, hatte aber kein Glück, auf die Länge meines Zielarrays zuzugreifen.

Handlebars.registerHelper('compare', function(lvalue, rvalue, options) {...})

"{{#each_with_index columns}}"+
"<div class='{{#equal index 0}} first{{/equal}}{{#equal index ../columns.length()}} last{{/equal}}'>"+
"</div>"+
"{{/each_with_index}}"

Kennt jemand eine Abkürzung, einen anderen Ansatz und einige gute Eigenschaften des Lenkers, die mich davon abhalten, in den Motor des Lenkers einzudringen, um den besten Kurs zu bestimmen?

techie.brandon
quelle
Ich würde die Vorlagenbibliothek von underscoreJS empfehlen. Sie ist viel sinnvoller und effizienter als handlebars.js
Austin,
1
Ähm, ich <3 unterstreiche genauso viel wie der nächste Typ, aber Sie haben sich Lenker eindeutig nie ernsthaft angesehen. Das Templating-System von Underscore kann (und wird es niemals versuchen) die Hälfte der Dinge tun, die Lenker können.
Machineghost
6
Ich habe nicht nach anderen Templating-Motoren gefragt. Ich habe meine Wahl vor vielen Iterationen getroffen. Viele Techniker bieten großartige Lösungen für dieses Problem, aber leider arbeite ich nicht mit diesen Technikern zusammen, sodass sie für mich derzeit nutzlos sind.
techie.brandon
Wenn Sie einfach "Anzeige" sprechen, können Sie mit CSS damit umgehen? Ich weiß , es ist ein Cop, aber wenn die Daten bereits auf dem Client ist, verstecken nur die mitstyle="display: none"
olore
Tatsächlich funktioniert die Verwendung von CSS nicht, da ich dies verwende, um anzugeben, welche Klasse verwendet werden soll. Wenn es zuerst in der Reihe steht (und als speziell befunden wird), erhält es eine spezielle Klasse, wenn es als letztes in der Reihe (und als besonders befunden wird) eine spezielle Klasse erhält (einige zusätzliche Variablen sagen mir, was die spezielle Klasse ist, also nicht Standard zu dieser Tabelle).
techie.brandon

Antworten:

113

Ab Handlebars v1.1.0 können Sie jetzt die Booleschen Werte @firstund @lastin jedem Helfer für dieses Problem verwenden:

{{#each foo}}
    <div class='{{#if @first}}first{{/if}}
                {{#if @last}} last{{/if}}'>
      {{@key}} - {{@index}}
    </div>
{{/each}}

Ein schneller Helfer, den ich geschrieben habe, um den Trick zu machen, ist:

Handlebars.registerHelper("foreach",function(arr,options) {
    if(options.inverse && !arr.length)
        return options.inverse(this);

    return arr.map(function(item,index) {
        item.$index = index;
        item.$first = index === 0;
        item.$last  = index === arr.length-1;
        return options.fn(item);
    }).join('');
});

Dann können Sie schreiben:

{{#foreach foo}}
    <div class='{{#if $first}} first{{/if}}{{#if $last}} last{{/if}}'></div>
{{/foreach}}
Kara Brightwell
quelle
Beeindruckende Arbeit! Ich habe noch nicht überprüft, ob es funktioniert, aber ich sehe so aus, als ob es funktionieren sollte. Wenn ja, werde ich es am Wochenende erneut besuchen und neu zuweisen. Vielen Dank!
techie.brandon
Ich habe gerade den oben genannten Helfer benutzt, genau wie angegeben gearbeitet ... danke! gist.github.com/zeroasterisk/5360895
zeroasterisk
5
Schöne Antwort, aber ich habe ein Auflegen bemerkt. Wenn das Element in Ihrem Array eine Zeichenfolge oder ein anderes Grundelement ist, können Sie ihm keine Eigenschaften anhängen. Meine Problemumgehung bestand darin, eine neue Zeichenfolge mit dem Wert von item zu erstellen, bei dem es sich technisch gesehen um ein Objekt handelt, und die Eigenschaften daran anzuhängen, wie in dieser Übersicht: https://gist.github.com/jordancooperman/5440241
jordancooperman
3
Warum wird diese Antwort akzeptiert, wenn die Antwort mit firstund lastMuttersprache effizienter ist?
Dan Dascalescu
1
Trägheit. Diese Antwort wurde vor zwei Jahren geschrieben und akzeptiert. Die Version von Lenker mit den nativen Konstrukten wurde vor etwas mehr als einem Jahr veröffentlicht. Ich vermute, das OP ist weitergegangen.
Kara Brightwell
156

Seit Lenker 1.1.0 ist der erste und letzte für jeden Helfer einheimisch geworden. Siehe Ticket Nr. 483 .

Die Verwendung ist wie in Eberanovs Helferklasse :

{{#each foo}}
    <div class='{{#if @first}}first{{/if}}{{#if @last}} last{{/if}}'>{{@key}} - {{@index}}</div>
{{/each}}
Jacob van Lingen
quelle
27
{{#unless @last}}, {{/ es sei denn}} FTW!
Crisboot
26

Wenn Sie nur versuchen, das erste Element des Arrays zu verarbeiten, kann dies hilfreich sein

{{#each data-source}}{{#if @index}},{{/if}}"{{this}}"{{/each}}

@index wird von jedem Helfer bereitgestellt und für das erste Element wäre es gleich Null und kann daher vom if-Helfer behandelt werden.

Yong Qu
quelle
7
Heads-up für alle, die dies gefunden haben und es mit Meteors Implementierung von Lenkern verwenden möchten, es wird nicht funktionieren. Das @ bricht alles.
Mike Turley
1

Lösung:

<div class='{{#compare index 1}} first{{/compare}}{{#compare index total}} last{{/compare}}'></div>

Nutzen Sie Helfer aus dem folgenden Blog und ...

https://gist.github.com/2889952

http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/

// {{#each_with_index records}}
//  <li class="legend_item{{index}}"><span></span>{{Name}}</li>
// {{/each_with_index}}

Handlebars.registerHelper("each_with_index", function(array, fn) {
  var total = array.length;
  var buffer = "";

  //Better performance: http://jsperf.com/for-vs-foreach/2
  for (var i = 0, j = total; i < j; i++) {
    var item = array[i];

    // stick an index property onto the item, starting with 1, may make configurable later
    item.index = i+1;
    item.total = total;
    // show the inside of the block
    buffer += fn(item);
  }

  // return the finished buffer
  return buffer;

});

Handlebars.registerHelper('compare', function(lvalue, rvalue, options) {

    if (arguments.length < 3)
        throw new Error("Handlerbars Helper 'compare' needs 2 parameters");

    operator = options.hash.operator || "==";

    var operators = {
        '==':       function(l,r) { return l == r; },
        '===':      function(l,r) { return l === r; },
        '!=':       function(l,r) { return l != r; },
        '<':        function(l,r) { return l < r; },
        '>':        function(l,r) { return l > r; },
        '<=':       function(l,r) { return l <= r; },
        '>=':       function(l,r) { return l >= r; },
        'typeof':   function(l,r) { return typeof l == r; }
    }

    if (!operators[operator])
        throw new Error("Handlerbars Helper 'compare' doesn't know the operator "+operator);

    var result = operators[operator](lvalue,rvalue);

    if( result ) {
        return options.fn(this);
    } else {
        return options.inverse(this);
    }

});

Beachten Sie, dass der Startindex korrekt 1 ist.

techie.brandon
quelle
Diese Antwort ist unvollständig ohne eine Definition von compareund total. Auch 0 ist der erste Index, nicht 1.
Kevin Borders
0

Ich habe den Helfer von Matt Brennan ein wenig verbessert. Sie können diesen Helfer mit Objekten oder Arrays verwenden. Für diese Lösung ist eine Unterstreichungsbibliothek erforderlich :

Handlebars.registerHelper("foreach", function(context, options) {
  options = _.clone(options);
  options.data = _.extend({}, options.hash, options.data);

  if (options.inverse && !_.size(context)) {
    return options.inverse(this);
  }

  return _.map(context, function(item, index, list) {
    var intIndex = _.indexOf(_.values(list), item);

    options.data.key = index;
    options.data.index = intIndex;
    options.data.isFirst = intIndex === 0;
    options.data.isLast = intIndex === _.size(list) - 1;

    return options.fn(item, options);
  }).join('');
});

Verwendung:

{{#foreach foo}}
    <div class='{{#if @first}}first{{/if}}{{#if @last}} last{{/if}}'>{{@key}} - {{@index}}</div>
{{/foreach}}
ebaranov
quelle
0

Nur zu Ihrer Information: Wenn Sie mit Lenkern <1.1.0 (wie ich) nicht weiterkommen, sollten Sie diese Problemumgehung ausprobieren:

Definieren Sie eine Eigenschaft wie isLastfür die Objekte, die Sie iterieren, und verwenden Sie sie wie

{{#each objectsInList}}"{{property}}": "{{value}}"{{#unless isLast}},{{/unless}}{{/each}}

um ein JSON-Objekt zu erstellen.

Ditti
quelle