Lenker / Schnurrbart - Gibt es eine integrierte Möglichkeit, die Eigenschaften eines Objekts zu durchlaufen?

216

Gibt es, wie der Titel der Frage sagt, eine Möglichkeit, die Objekteigenschaften eines Schnurrbartes / Lenkers zu durchlaufen ?

Also mit

var o = {
  bob : 'For sure',
  roger: 'Unknown',
  donkey: 'What an ass'
}

Kann ich dann in der Template-Engine etwas tun , das äquivalent wäre?

for(var prop in o)
{
    // with say, prop a variable in the template and value the property value
}

?

Ben
quelle

Antworten:

448

Eingebaute Unterstützung seit Lenker 1.0rc1

Die Unterstützung für diese Funktionalität wurde zu Handlebars.js hinzugefügt , sodass keine externen Helfer mehr erforderlich sind.

Wie man es benutzt

Für Arrays:

{{#each myArray}}
    Index: {{@index}} Value = {{this}}
{{/each}}

Für Objekte:

{{#each myObject}}
    Key: {{@key}} Value = {{this}}
{{/each}}

Beachten Sie, dass nur Eigenschaften hasOwnPropertyaufgelistet werden, die den Test bestehen.

Jon
quelle
2
@ Rafi: Man kann das nicht viel verstehen, ohne die Datenstruktur zu kennen.
Jon
3
@ Rafi: meinst du nicht {{this.title}}?
Nevyn
2
@qodeninja: Einfach: genauso wie Sie sich auf die Werte in den obigen Beispielen beziehen - mit {{#each this}}. Ihre Auswahl an Begriffen ist ebenfalls verwirrend (was macht ein Objekt zur "obersten Ebene" und ein anderes nicht? Was sind genau "vordefinierte" Schlüssel? Usw.), daher möchten Sie diese Konzepte möglicherweise erneut betrachten.
Jon
1
Wenn nicht falsch, dann nur mit v1.1.0 ist dies verfügbar, aber tolle Antwort danke.
Renars Sirotins
2
Wie machen Sie das nur für eine bestimmte Whitelist von Eigenschaften?
Marco Prins
70

Es ist eigentlich ganz einfach als Helfer zu implementieren:

Handlebars.registerHelper('eachProperty', function(context, options) {
    var ret = "";
    for(var prop in context)
    {
        ret = ret + options.fn({property:prop,value:context[prop]});
    }
    return ret;
});

Dann benutze es so:

{{#eachProperty object}}
    {{property}}: {{value}}<br/>
{{/eachProperty }}
Ben
quelle
2
Sieht gut aus. Müssen Sie der Schleife eine hasOwnProperty-Prüfung hinzufügen, damit Sie nicht über die Eigenschaften des Prototyps iterieren?
Affenjunge
Tolle Lösung @Ben. Falls jemand versucht, dies mit Ember zu verwenden, finden Sie in meiner Antwort unten die Lösung, damit es funktioniert.
Flynfish
27

BEARBEITEN: Der Lenker verfügt jetzt über eine integrierte Methode, um dies zu erreichen. siehe die ausgewählte Antwort oben. Bei der Arbeit mit normalem Schnurrbart gilt weiterhin Folgendes.

Moustache kann Elemente in einem Array durchlaufen. Daher würde ich vorschlagen, ein separates Datenobjekt zu erstellen, das so formatiert ist, dass Moustache damit arbeiten kann:

var o = {
  bob : 'For sure',
  roger: 'Unknown',
  donkey: 'What an ass'
},
mustacheFormattedData = { 'people' : [] };

for (var prop in o){
  if (o.hasOwnProperty(prop)){
    mustacheFormattedData['people'].push({
      'key' : prop,
      'value' : o[prop]
     });
  }
}

Nun wäre Ihre Moustache-Vorlage ungefähr so:

{{#people}}
  {{key}} : {{value}}
{{/people}}

Lesen Sie hier den Abschnitt "Nicht leere Listen": https://github.com/janl/mustache.js

Amit
quelle
1
Ich bin Ihrem Vorschlag gefolgt, da ich ohnehin einige zusätzliche Untereigenschaften übergeben muss. Danke für die Hilfe!
Ben
Vielen Dank, Ihre Idee hat mir einen weiteren Tag der Suche nach Alternativen erspart. Diese Zeile ist der Schlüssel mustacheFormattedData = {'people': []};
Matt
Wie würden Sie dies mit einem Array von "o" -Objekten tun?
Red888
4

Dies ist die Antwort von @ Ben, die für die Verwendung mit Ember aktualisiert wurde. Beachten Sie, dass Sie sie verwenden müssen Ember.get da der Kontext als Zeichenfolge übergeben wird.

Ember.Handlebars.registerHelper('eachProperty', function(context, options) {
  var ret = "";
  var newContext = Ember.get(this, context);
  for(var prop in newContext)
  {
    if (newContext.hasOwnProperty(prop)) {
      ret = ret + options.fn({property:prop,value:newContext[prop]});
    }
  }
  return ret;
});

Vorlage:

{{#eachProperty object}}
  {{key}}: {{value}}<br/>
{{/eachProperty }}
Flynfish
quelle
Danke @flynfish. Kontext ist eine Zeichenfolge in Ember? das scheint .. etwas seltsam.
Ben
Ja, ich bin mir nicht sicher, da ich neu bei Ember bin und immer noch versuche, mich darin zurechtzufinden.
Flynfish
1

Die Antwort von @ Amit ist gut, da sie sowohl im Schnurrbart als auch im Lenker funktioniert.

In Bezug auf Nur-Lenker-Lösungen habe ich einige gesehen und ich mag den each_with_keyBlock-Helfer unter https://gist.github.com/1371586 am besten.

  • Sie können damit über Objektliterale iterieren, ohne sie zuerst umstrukturieren zu müssen
  • Sie haben die Kontrolle darüber, was Sie als Schlüsselvariable bezeichnen. Bei vielen anderen Lösungen müssen Sie vorsichtig sein, wenn Sie Objektschlüssel mit dem Namen 'key'oder 'property'usw. verwenden.
mjumbewu
quelle
Schöner Fund. Nur eine Warnung an andere Leser: Der "key_value" -Helfer in dieser Liste enthält einen Fehler. Lesen Sie die Kommentare, um das Problem zu beheben.
Sirentian
0

Vielen Dank für Bens Lösung, meinen Anwendungsfall, um nur bestimmte Felder der Reihe nach anzuzeigen

mit Objekt

Code:

    handlebars.registerHelper('eachToDisplayProperty', function(context, toDisplays, options) {
    var ret = "";
    var toDisplayKeyList = toDisplays.split(",");
    for(var i = 0; i < toDisplayKeyList.length; i++) {
        toDisplayKey = toDisplayKeyList[i];
        if(context[toDisplayKey]) {
            ret = ret + options.fn({
                property : toDisplayKey,
                value : context[toDisplayKey]
            });
        }

    }
    return ret;
});

Quellobjekt:

   { locationDesc:"abc", name:"ghi", description:"def", four:"you wont see this"}

Vorlage:

{{#eachToDisplayProperty this "locationDesc,description,name"}}
    <div>
        {{property}} --- {{value}}
    </div>
    {{/eachToDisplayProperty}}

Ausgabe:

locationDesc --- abc
description --- def
name --- ghi
vincentlcy
quelle
0

Dies ist eine Hilfsfunktion für MoustacheJS, ohne die Daten vorformatieren und stattdessen beim Rendern abrufen zu müssen.

var data = {
    valueFromMap: function() {
        return function(text, render) {
            // "this" will be an object with map key property
            // text will be color that we have between the mustache-tags
            // in the template
            // render is the function that mustache gives us

            // still need to loop since we have no idea what the key is
            // but there will only be one
            for ( var key in this) {
                if (this.hasOwnProperty(key)) {
                    return render(this[key][text]);
                }
            }
        };
    },

    list: {
        blueHorse: {
            color: 'blue'
        },

        redHorse: {
            color: 'red'
        }
    }
};

Vorlage:

{{#list}}
    {{#.}}<span>color: {{#valueFromMap}}color{{/valueFromMap}}</span> <br/>{{/.}}
{{/list}}

Ausgänge:

color: blue
color: red

(Die Reihenfolge kann zufällig sein - es ist eine Karte.) Dies kann nützlich sein, wenn Sie das gewünschte Kartenelement kennen. Achten Sie einfach auf falsche Werte.

Kraftstoff
quelle
-1

Ich habe eine alte Version verwendet 1.0.beta.6 des Lenkers verwendet. Ich glaube, irgendwo zwischen 1.1 und 1.3 wurde diese Funktionalität hinzugefügt. Durch die Aktualisierung auf 1.3.0 wurde das Problem behoben. Hier ist die Verwendung:

Verwendung:

{{#each object}}
  Key {{@key}} : Value {{this}}
{{/people}}
AamirR
quelle