Mustache.js: Zugriff auf den übergeordneten Bereich

Erstellt am 11. Dez. 2014  ·  18Kommentare  ·  Quelle: janl/mustache.js

Zugriff auf den übergeordneten Bereich

In Anbetracht :

node = {
  id: 1,
  children : [
      { id : 2 },
      { id : 3 }
  ]
}

Und folgende Vorlage:

{{ id }} {# will output node.id #}
{{#children}}
    {{children.id}}  {# will output node.children[i].id #}
    {{id}}  {# will also output node.children[i].id #}
{{/children}}

So wie es ist, müssen Sie manchmal auf die übergeordnete Eigenschaft zugreifen (zum Beispiel in einem verschachtelten Knotenmodell).
Es kann einfach implementiert werden, indem Sie "../" verwenden, um den übergeordneten Geltungsbereich zu erhalten

Ex :

{{ id }} {# will output node.id #}
{{#children}}
    {{children.id}}  {# will output node.children[i].id #}
    {{id}}  {# will also output node.children[i].id #}
    {{ ../id }}  {# will output node.id #}
{{/children}}

Um das zu erreichen:

  Context.prototype.lookup = function (name) {
    var cache = this.cache;

    var value;
    if (name in cache) {
      console.log(name + ' found');
      value = cache[name];
    } else {
      var context = this, names, index;

      while (context) {
        if (name.indexOf('.') > 0) {
          value = context.view;
          names = name.split('.');
          index = 0;

          while (value != null && index < names.length)
            value = value[names[index++]];
        } else if(name.match(/^\.\.\//)) {
          name = name.replace(/^\.\.\//, '');
        } else {
          value = context.view[name];
        }

        if (value != null)
          break;

        context = context.parent;
      }

      cache[name] = value;
    }

    if (isFunction(value))
      value = value.call(this.view);

    return value;
  };
Future Plugin

Hilfreichster Kommentar

Richtig. Den Lenker habe ich komplett vergessen.

Lässt Benutzer an Lenker verlieren.
Das ist eine akzeptable Designentscheidung.

Alle 18 Kommentare

Das ist nicht in den Spezifikationen von mustache , oder? Gibt es dafür keinen Workaround? Ich bin überrascht, dass noch niemand auf diese Einschränkung gestoßen ist.

Ich stimme zu, dass es oft erforderlich ist, auf Dinge im übergeordneten Bereich zuzugreifen. Mein pragmatischer Ansatz war immer, mehrdeutige Eigenschaftsnamen zu vermeiden. Das hat bei mir lange funktioniert, obwohl es oft zu seltsamen Objekten führt.

Apropos Erfahrung mit Lenkern; Diese Fähigkeit könnte Leute dazu verleiten, verrückte, verworrene Parent-Scope-Auflösungen zu erstellen: {{../../../id}} ist viel schwieriger zu begreifen als {{movieId}} .

Es stimmt, dass die Verwendung von "../" zur Unlesbarkeit führen kann. Aber auf die andere Weise kann die Verwendung von caml zum Auflösen von Parent nicht erreicht werden, da Sie caml im lokalen Bereich haben können. Darüber hinaus würde die Definition eines Schlüsselworts für den Zugriff auf Eltern die Moustache-Philosophie meiner Meinung nach nicht respektieren.

Ehrlich gesagt könnte ich zu keiner einfacheren und besseren Idee kommen, als die Verzeichnisdarstellung zu verwenden.

Ja, das Vermeiden mehrdeutiger Eigenschaftsnamen führt auch zu lesbareren/ausführlicheren Vorlagen. Aber ich verstehe, warum manche Leute diese Funktion mögen würden.

Wie wäre es, ein separates Paket zu schreiben, das das Innenleben von mustache.js modifiziert, um die gewünschte Funktion hinzuzufügen? Ein bisschen wie ein Plugin.

Um ehrlich zu sein, sehe ich dies nur über ein Plugin oder ein Pragma. Und eine Plugin-API scheint derzeit nicht die Priorität zu haben.

Darüber habe ich noch ein bisschen nachgedacht...

Ich glaube, die Philosophie von Moustache besteht nicht darin, Daten _as-is__ an den Renderer zu übergeben, sondern sie im Voraus in eine Ansicht zu „vorbereiten“. Sie hätten dann eine parentId Eigenschaft in Ihren Knoten.

Es ist auch einfacher, Vorlagen mit ausführlicheren Variablen zu lesen und zu verwalten:

{{ id }}
{{#children}}
    {{children.id}}
    {{id}}
{{/children}}

Vorher vs Nachher

{{ nodeId }}
{{#children}}
    {{ nodeId }}
    {{ parentId }}
{{/children}}

Relevant: http://stackoverflow.com/questions/4067093/mustache-read-variables-from-parent-section-in-child-section

(Entschuldigung, dass ich dich @bobthecow beschwöre, aber ich weiß deine Schnurrbart-Weisheit immer zu schätzen :lächeln:)

Sie können bereits nach oben gehen, also müssen Sie nur die Daten mit einem temporären Objekt {node: ... } , die Vorlage mit {{#node}}...{{/node}} und dann {{node.id}} umschließen, um das Problem zu beheben, das mit der ersten Vorlage angezeigt wird to_html() die Vorlage erstellen ...

fühlt sich wie ein lückenhafter Work-Around an. Es funktioniert auch nur mit vereinfachten 2-Ebenen-Modellen, bei denen Sie durch eine Umschlagverpackung für die äußere Schicht lösen können. Aber was ist, wenn das Modell tiefer ist? das fühlt sich an wie jonglieren.

Oft muss ich ein Modell binden, das ich von niedrigeren Datenschichten bekomme, und meine Aufgabe ist es, es zu präsentieren - in welcher Form auch immer ich es aus der Infra habe. Der Vorschlag hier ist, dass ich das Modell rekursiv ganz tief in einen vorzeigbaren Zustand umwandeln muss - was hier in Betracht gezogen würde redable property names .
Das entspricht nicht bequem der Realität...
Ja, stimmt, es koppelt die Vorlage mit dem Modell. Aber können Sie mir eine Vorlage zeigen, die nicht an konkrete Modellregeln gekoppelt ist? Alle Vorlagen werden per Definition erstellt, um ein definiertes Modell zu rendern.
Eine andere Schicht verschiebt die Definitionsschicht einen Schritt zurück und erfordert eine Übersetzungsschicht - was umständlich und nicht immer notwendig ist

IMHO denke ich, dass das Tool dem Benutzer die Wahl lassen sollte, anstatt rechthaberische Regeln aufzuerlegen

Für Leser ein Beispiel dafür, was @rndme vorschlägt:

const Mustache = require('mustache')

var view = {
  node: {
    id: 5,
    children: [ { id: 6 }, { id: 7 } ]
  }
}

const template = `
{{#node}}
  children:
  {{#children}}

    id: {{ id }}
    parentId: {{ node.id }}
  {{/children}}
{{/node}}
`

const output = Mustache.render(template, view)
console.log(output)

  children:

    id: 6
    parentId: 5

    id: 7
    parentId: 5

Die Verwendung der folgenden Vorlage funktioniert ab latest , aber _sollte funktionieren_, imo.

const template = `
  children:
  {{#node.children}}

    id: {{ id }}
    parentId: {{ node.id }}
  {{/node.children}}
`

Ja, stimmt, es koppelt die Vorlage mit dem Modell. Aber können Sie mir eine Vorlage zeigen, die nicht an konkrete Modellregeln gekoppelt ist? Alle Vorlagen werden per Definition erstellt, um ein definiertes Modell zu rendern.
Eine andere Schicht verschiebt die Definitionsschicht einen Schritt zurück und erfordert eine Übersetzungsschicht - was mühsam und nicht immer notwendig ist

Afaik, die Philosophie von Moustache war immer, dass Sie eine Ansicht generieren, die an die Vorlage übergeben wird – Sie übergeben das Modell nicht direkt.

@osher Kannst du uns ein Beispiel zeigen, das du mit dem oben genannten Tipp/Trick nicht so einfach

Ich werde versuchen, Snippets später bereitzustellen, aber im Grunde - mit einer Verschachtelung auf 3 Ebenen wird es nicht funktionieren, da Sie die mittlere Ebene nicht umschließen können - müssen Sie die Quelle in eine verarbeitete Ansicht umwandeln.
Sie können auf die umschlossene oberste Ebene zugreifen, aber Sie haben keine Lösung für die mittlere Ebene.

Nehmen Sie zum Beispiel ein Prahlerei-Dokument, in dem Sie Wurzelebene, Pfadebene, Verbebene haben (und es gibt noch mehr, aber lasst uns hier aufhören). Jede Ebene kann eine benutzerdefinierte Anweisung angeben - x-uses , die eine DI-Anweisung für die Implementierungsschicht ist.

Angenommen, Sie möchten aus diesem Prahlerei-Dokument HTML-Dokumente generieren.
Sie benötigen eine flache Tabelle, die für jeden Operationshandler (die Verbebene) die DI angibt, die er akzeptiert, und von welcher Schicht er es erbt.
Während alle Informationen in der Prahlerei-Dokumentation enthalten sind, haben Sie jetzt ein Problem.

Nächste.
Versuchen Sie, Schnurrbart zu verwenden, um den Code zu generieren, der die im Dokument beschriebene API implementiert, die Scheinantworten basierend auf der Standardantwort des Vorgangs zurückgibt.
Versuchen Sie, Doclets zu generieren, die beschreiben, was der implementierende Entwickler, der die Scheinantwort durch echte Logik ersetzt, in seinem DI-Kontext erwarten sollte, und genau angeben, auf welcher Ebene er es erhält.
Dasselbe...

Keine klassische HTML-Generierung - ja. aber wer hat gesagt, dass Schnurrbart nur für HTML ist? es ist eine Template-Engine, und die Codegenerierung wird häufig mit solchen Template-Engines implementiert ;)

Sie passieren das Modell nicht direkt.

das sollte die Wahl des Benutzers sein, keine Einschränkung / Einschränkung

Ich gebe Ihnen noch ein Beispiel, und ich werde versuchen, es zu tun, ohne geheime Soße zu verraten.

Nehmen Sie eine Baumdatenstruktur an, die Vermögenswerte beschreibt, die einem Spieler in einem Strategiespiel gehören.
Der Baum kann etwa 5 Ebenen haben, zum Beispiel:
Aliance -> Empire -> City -> Army -> Troops

Jede Stufe kann einen Modifikatorbonus - zum Beispiel - oder einen Angriffsbonus, Verteidigungsbonus, Gesundheitsbonus usw.
Modifikatoren, die dieselben Statistiken ansprechen, werden in allen Ebenen mit demselben Namen beschrieben (hauptsächlich, weil sie rekursiv berechnet werden).
Sie müssen die Vorlagen-Engine verwenden, um einen Kampfsimulator zu präsentieren, der den Spielern helfen soll, die ideale Armee für eine bestimmte Herausforderung auszuwählen, indem die Kampfstatistiken der Truppen in der Armee angezeigt werden – die sich auf den untersten Ebenen befinden, aber Schlachten sammeln Modifikatoren, die in der gesamten Struktur nach demselben Attributnamen benannt sind.
Dies ist _sehr_ vereinfacht, basiert aber auf einer wahren Begebenheit, bei der andere Tools das Problem mit großer Leichtigkeit lösten, ohne dass eine mittlere Übersetzungsschicht erforderlich war.

Ich werde die Schwierigkeit hinzufügen: Manchmal werden Armeen in Task Forces auf Allianzebene zugewiesen.
Alliance -> Rally -> Troops
Das Werkzeug sollte generisch genug sein (einfach rekursiv) und nicht von konkreten Ebenen abhängen.

Ich habe es mit dem gelöst, was Schnurrbart Partials nennen wird, nur dass ich keinen Schnurrbart verwendet habe ...

@osher sagte:

das sollte die Wahl des Benutzers sein, keine Einschränkung / Einschränkung

Es besteht kein Zweifel, dass Schnurrbart Meinungen hat. Seine Philosophie der "logiklosen Vorlagen" schränkt die Vorlagen stark ein. Diese Tatsache erfordert oft eine Daten-/Modellvorbereitung, bevor sie der Vorlage zum Rendern übergeben wird. Wenn dies nicht Ihren Anforderungen entspricht, gibt es Alternativen, die möglicherweise besser sind, wie z. B. Lenker oder sogar lodash.template, um nur einige zu nennen

Richtig. Den Lenker habe ich komplett vergessen.

Lässt Benutzer an Lenker verlieren.
Das ist eine akzeptable Designentscheidung.

Ich bin mir ziemlich sicher, dass @osher sarkastisch war, als er sagte "Das ist eine akzeptable Designentscheidung.", aber dieses Thema wurde seit 2016 aufgegeben. Was ist los? Es scheint, als ob diese Frage sowohl in diesem JavaScript-Repository als auch im Haupt-Repository vermieden wird:
https://github.com/mustache/mustache.github.com/issues/103

Ich für meinen Teil denke, dass die Möglichkeit, auf den übergeordneten Geltungsbereich zu verweisen, logischlos ist und die Schnurrbart-Ideale nicht beeinträchtigen sollte.

Ich mag die Idee, immer mit einem Symbol wie einem führenden "../" auf den Root-Bereich zugreifen zu können:

Mustache.render('{{a1}}{{#a}}{{b.c}}{{../a1}}{{/a}}',{"a":{"b":{"c":"x1"}},"a1":"x2"})
"x2x1"

Ich möchte, dass dies "x2x1x2" rendert, aber es lässt das letzte aus, weil es nicht so funktioniert.
Ich dachte, ich würde empfehlen, so etwas wie JSONPath zu verwenden: https://goessner.net/articles/JsonPath/index.html#e2 Im Gegensatz zu XPath für XML wird der übergeordnete Operator jedoch nicht empfohlen/implementiert, was ich erhofft hatte Pro.

Vielleicht könnte Moustache einfach versuchen, mit Lenkstangen kompatibel zu bleiben und die ../ Syntax für den übergeordneten Kontext zu verwenden?

AFAIK, handlebars ist nur JS, während Moustache dieselbe Syntax in vielen Umgebungen verwendet, zum Beispiel PHP. Wenn Sie die Schnurrbart-Syntax ändern möchten, müssen Sie alle anderen Nicht-Js-Implementierungen davon überzeugen, dasselbe zu tun; Eine große Bestellung. Darüber hinaus fand ich es beim Ändern des JS-Codes problematisch, "eine Ebene" nach oben zu gehen, obwohl ich in meinem Fork eine Möglichkeit hinzugefügt einfach zu implementieren war ...

Irgendwas dazu?

Es muss auch Dokumentation und Stilempfehlungen für Situationen geben, in denen die Punktnotation optional ist.

view = { wrap: { txt: "test" } };
{{#wrap}}
  {{wrap.txt}} {{! Should I use this?}}
  {{txt}} {{! Or this?}}
{{/wrap}}

Weitere Details hier: https://stackoverflow.com/q/62166467/5637701

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

funston picture funston  ·  7Kommentare

kuldeepdhaka picture kuldeepdhaka  ·  9Kommentare

rlightner picture rlightner  ·  7Kommentare

Immortalin picture Immortalin  ·  12Kommentare

ForbesLindesay picture ForbesLindesay  ·  14Kommentare