555 Stimmen

Logischer Operator in einer Handlebars.js {{#if}} Bedingung

Gibt es eine Möglichkeit, in Handlebars JS logische Operatoren in den Standard-Handlebars.js-Bedingungsoperator einzubinden? Etwas wie das:

{{#if section1 || section2}}
.. Inhalt
{{/if}}

Ich weiß, ich könnte meinen eigenen Helfer schreiben, aber ich möchte zuerst sicherstellen, dass ich nicht das Rad neu erfinde.

1 Stimmen

Für die "und" Logik können Sie verschachtelte if-Bedingungen verwenden, aber es ist umständlich und hilft Ihnen nicht beim "sonst", oder bei einer "oder" Logik wie in Ihrer obigen Frage.

579voto

Nick Kitto Punkte 5928

Dies ist möglich, indem man mit einem Block-Helper 'trickst'. Dies geht wahrscheinlich gegen die Ideologie der Entwickler von Handlebars.

Handlebars.registerHelper('ifCond', function(v1, v2, options) {
  if(v1 === v2) {
    return options.fn(this);
  }
  return options.inverse(this);
});

Sie können dann den Helper im Template wie folgt aufrufen

{{#ifCond v1 v2}}
    {{v1}} ist gleich {{v2}}
{{else}}
    {{v1}} ist nicht gleich {{v2}}
{{/ifCond}}

66 Stimmen

Dies widerspricht zwar der logiklosen Natur von Handlebars / Moustache, ist aber dennoch definitiv nützlich, danke!

6 Stimmen

Bitte beachten Sie, dass dies einfach nicht mit gebundenen Eigenschaften funktioniert (lesen, Ember Bindungen). Es funktioniert mit literalen Werten, löst aber keine Modell Eigenschaften auf (getestet mit Ember 1.0.0-rc.8 und Handlebars 1.0.0), und registerBoundHelper kann nicht mit Handlebars-Syntax umgehen. Der Workaround besteht darin, eine benutzerdefinierte Ansicht zu erstellen: stackoverflow.com/questions/18005111/…

0 Stimmen

In Ember sollten Sie stattdessen eine berechnete Eigenschaft für den Wert erstellen und diese Eigenschaft in Ihrem Template verwenden. Auf diese Weise funktionieren die Bindungen korrekt.

514voto

Jim Punkte 812

Den Lösungsweg einen Schritt weiter führen. Dies fügt den Vergleichsoperator hinzu.

Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {

    switch (operator) {
        case '==':
            return (v1 == v2) ? options.fn(this) : options.inverse(this);
        case '===':
            return (v1 === v2) ? options.fn(this) : options.inverse(this);
        case '!=':
            return (v1 != v2) ? options.fn(this) : options.inverse(this);
        case '!==':
            return (v1 !== v2) ? options.fn(this) : options.inverse(this);
        case '<':
            return (v1 < v2) ? options.fn(this) : options.inverse(this);
        case '<=':
            return (v1 <= v2) ? options.fn(this) : options.inverse(this);
        case '>':
            return (v1 > v2) ? options.fn(this) : options.inverse(this);
        case '>=':
            return (v1 >= v2) ? options.fn(this) : options.inverse(this);
        case '&&':
            return (v1 && v2) ? options.fn(this) : options.inverse(this);
        case '||':
            return (v1 || v2) ? options.fn(this) : options.inverse(this);
        default:
            return options.inverse(this);
    }
});

Verwenden Sie es in einer Vorlage wie folgt:

{{#ifCond var1 '==' var2}}

Coffee Script version

Handlebars.registerHelper 'ifCond', (v1, operator, v2, options) ->
    switch operator
        when '==', '===', 'is'
            return if v1 is v2 then options.fn this else options.inverse this
        when '!=', '!=='
            return if v1 != v2 then options.fn this else options.inverse this
        when '<'
            return if v1 < v2 then options.fn this else options.inverse this
        when '<='
            return if v1 <= v2 then options.fn this else options.inverse this
        when '>'
            return if v1 > v2 then options.fn this else options.inverse this
        when '>='
            return if v1 >= v2 then options.fn this else options.inverse this
        when '&&', 'and'
            return if v1 and v2 then options.fn this else options.inverse this
        when '||', 'or'
            return if v1 or v2 then options.fn this else options.inverse this
        else
            return options.inverse this

23 Stimmen

Vergiss nicht '||' und '&&'. Ich habe diese Fälle hinzugefügt und sie sind sehr nützlich.

22 Stimmen

Als Neuling im Umgang mit Handlebars war mir nicht sofort klar, dass du den Operator als Zeichenkette übergeben musst, da sonst der Compiler bei der Tokenisierung deines Templates einen Fehler erzeugt. {{#ifCond true '==' false}}

0 Stimmen

Wenn ich Ember mit Rails verwende, wo sollte ich das definieren? In welcher Datei sollte ich diesen Code platzieren? Danke.

232voto

kevlened Punkte 10228

Handlebars unterstützt verschachtelte Operationen. Dies bietet eine Menge Flexibilität (und saubereren Code), wenn wir unsere Logik etwas anders schreiben.

{{#if (or section1 section2)}}
.. Inhalt
{{/if}}

Tatsächlich können wir alle Arten von Logik hinzufügen:

{{#if (or 
        (eq section1 "foo")
        (ne section2 "bar"))}}
.. Inhalt
{{/if}}

Registrieren Sie einfach diese Helfer:

Handlebars.registerHelper({
    eq: (v1, v2) => v1 === v2,
    ne: (v1, v2) => v1 !== v2,
    lt: (v1, v2) => v1 < v2,
    gt: (v1, v2) => v1 > v2,
    lte: (v1, v2) => v1 <= v2,
    gte: (v1, v2) => v1 >= v2,
    and() {
        return Array.prototype.every.call(arguments, Boolean);
    },
    or() {
        return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
    }
});

5 Stimmen

Beachten Sie, dass dies erst mit HTMLBars in Ember 1.10 möglich war. Außerdem sind diese Helfer als ein Ember CLI-Addon verfügbar, wenn Sie möchten: github.com/jmurphyau/ember-truth-helpers.

1 Stimmen

Auf diese Weise ist es besser, ohne Optionen mit der if-Methode zu bleiben und einfacher zu testen. Danke!

42 Stimmen

Wir scheinen Lisp in Handlebars integriert zu haben.

95voto

bentael Punkte 1917

Heben wir das Ganze auf ein neues Level, für diejenigen von euch, die am Limit leben.

Zusammenfassung: https://gist.github.com/akhoury/9118682 Demo: Code-Schnipsel unten

Handlebars Helper: {{#xif AUSDRUCK}} {{else}} {{/xif}}

Ein Helper zur Ausführung einer IF-Anweisung mit beliebigem Ausdruck

  1. AUSDRUCK ist ein ordnungsgemäß maskierter String
  2. Ja, du MUSST die Zeichenketten ordnungsgemäß maskieren oder einfach einzelne und doppelte Anführungszeichen abwechseln
  3. Du kannst auf jede globale Funktion oder Eigenschaft zugreifen, z.B. encodeURIComponent(property)
  4. Dieses Beispiel setzt voraus, dass du diesen Kontext an dein Handlebars template( {name: 'Sam', age: '20' } ) übergeben hast; beachte, dass age eine string ist, nur um später in diesem Beitrag parseInt() vorzuführen

Verwendung:

 {{#xif " name == 'Sam' && age === '12' " }}
   BOOM
 {{else}}
   BAMM
 {{/xif}}

Ausgabe

  BOOM

JavaScript: (es hängt von einem anderen Helper ab - lies weiter)

 Handlebars.registerHelper("xif", function (expression, options) {
    return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
  });

Handlebars Helper: {{x AUSDRUCK}}

Ein Helper zur Ausführung von JavaScript-Ausdrücken

  1. AUSDRUCK ist ein ordnungsgemäß maskierter String
  2. Ja, du MUSST die Zeichenketten ordnungsgemäß maskieren oder einfach einzelne und doppelte Anführungszeichen abwechseln
  3. Du kannst auf jede globale Funktion oder Eigenschaft zugreifen, z.B. parseInt(property)
  4. Dieses Beispiel setzt voraus, dass du diesen Kontext an dein Handlebars template( {name: 'Sam', age: '20' } ) übergeben hast; age ist eine string zur Demonstration, es kann alles sein..

Verwendung:

Url: {{x "'hi' + name + ', ' + window.location.href + ' <---- das ist dein href,' + ' dein Alter ist:' + parseInt(this.age, 10)"}}

Ausgabe:

Url: hi Sam, http://example.com <---- das ist dein href, dein Alter ist: 20

JavaScript:

Dies wirkt etwas umfangreich, weil ich die Syntax erweitert und fast jede Zeile kommentiert habe, um die Klarheit zu gewährleisten

Handlebars.registerHelper("x", function(expression, options) {
  var result;

  // you can change the context, or merge it with options.data, options.hash
  var context = this;

  // yup, i use 'with' here to expose the context's properties as block variables
  // you don't need to do {{x 'this.age + 2'}}
  // but you can also do {{x 'age + 2'}}
  // HOWEVER including an UNINITIALIZED var in a expression will return undefined as the result.
  with(context) {
    result = (function() {
      try {
        return eval(expression);
      } catch (e) {
        console.warn('•Expression: {{x \'' + expression + '\'}}\n•JS-Error: ', e, '\n•Context: ', context);
      }
    }).call(context); // to make eval's lexical this=context
  }
  return result;
});

Handlebars.registerHelper("xif", function(expression, options) {
  return Handlebars.helpers["x"].apply(this, [expression, options]) ? options.fn(this) : options.inverse(this);
});

var data = [{
  firstName: 'Joan',
  age: '21',
  email: 'joan@aaa.bbb'
}, {
  firstName: 'Sam',
  age: '18',
  email: 'sam@aaa.bbb'
}, {
  firstName: 'Perter',
  lastName: 'Smith',
  age: '25',
  email: 'joseph@aaa.bbb'
}];

var source = $("#template").html();
var template = Handlebars.compile(source);
$("#main").html(template(data));

h1 {
  font-size: large;
}
.content {
  padding: 10px;
}
.person {
  padding: 5px;
  margin: 5px;
  border: 1px solid grey;
}

  <div class="content">
    {{#each this}}
    <div class="person">
      <h1>{{x  "'Hi ' + firstName"}}, {{x 'lastName'}}</h1>
      <div>{{x '"you were born in " + ((new Date()).getFullYear() - parseInt(this.age, 10)) '}}</div>
      {{#xif 'parseInt(age) >= 21'}} login here:
      <a href="http://foo.bar?email={{x 'encodeURIComponent(email)'}}">
            http://foo.bar?email={{x 'encodeURIComponent(email)'}}
        </a>
      {{else}} Bitte komm wieder, wenn du erwachsen bist. {{/xif}}
    </div>
    {{/each}}
  </div>

Mehr

Wenn du auf den übergeordneten Scope zugreifen möchtest, ist dieser etwas anders, der Ausdruck ist die VERKNÜPFUNG aller Argumente, Verwendung: Angenommen, der Datenkontext sieht so aus:

// data
{name: 'Sam', age: '20', address: { city: 'yomomaz' } }

// im Template
// beachte, wie der Ausdruck alle Strings mit Anführungszeichen umschließt und sogar die Variablen
// da sie als Strings an den Helper übergeben werden
// probiere es aus, du wirst sofort die fehlerhaften Ausdrücke sehen und es herausfinden

{{#with address}}
    {{z '"hi " + "' ../this.name '" + " you live with " + "' city '"' }}
{{/with}}

Javascript:

Handlebars.registerHelper("z", function () {
    var options = arguments[arguments.length - 1]
    delete arguments[arguments.length - 1];
    return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]);
});

Handlebars.registerHelper("zif", function () {
    var options = arguments[arguments.length - 1]
    delete arguments[arguments.length - 1];
    return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]) ? options.fn(this) : options.inverse(this);
});

16 Stimmen

Das ist großartig. Handlebars kann dir nicht sagen, was du tun sollst :)

1 Stimmen

:) danke, ich habe das Gist ein wenig aktualisiert, um ein paar weitere Goodies hinzuzufügen (die nicht direkt mit dieser SO-Frage zusammenhängen - aber im Geiste dessen, was du innerhalb einer Handlebars-Vorlage tun möchtest). Du solltest jedoch auf die Einschränkungen achten, ich habe noch keinen Weg gefunden, um auf "obere Scope-Level" innerhalb des Ausdrucks zuzugreifen, sagen wir du bist in einem each-Scope, {{#each}} ... {{xif ' ../name === this.name' }} {{/each}} ... aber ich bin immer noch am Untersuchen..

1 Stimmen

Fand eine Lösung für "Zugriff auf den oberen Bereich", indem ich einen neuen Helfer verwendete, siehe aktualisierte Antwort, {{z ...}} Helfer

44voto

Jono Punkte 3183

Es gibt eine einfache Möglichkeit, dies zu tun, ohne eine Hilfsfunktion zu schreiben... Es kann vollständig innerhalb des Templates erledigt werden.

{{#if cond1}}   
  {{#if con2}}   
     und Bedingung erfüllt  
  {{/if}}
{{else}}   
   beide Bedingungen waren nicht wahr  
{{/if}}

Bearbeitung: Alternativ können Sie Oder-Bedingungen machen, indem Sie Folgendes tun:

{{#if cond1}}  
   Oder-Bedingung erfüllt    
{{else}}   
  {{#if cond2}}  
     Oder-Bedingung erfüllt  
  {{else}}      
     Keine der Bedingungen war wahr    
  {{/if}}  
{{/if}}

Bearbeitung/Hinweis: Von der Handlebar-Website: handlebarsjs.com hier sind die falschen Werte:

Sie können den if-Helfer verwenden, um bedingt einen Block zu rendern. Wenn sein Argument false, undefined, null, "" oder [] (ein "falsy"-Wert) zurückgibt, dann wird jede 'cond' (wie cond1 oder cond2) nicht als wahr betrachtet.

15 Stimmen

Nicht wirklich, du vergleichst nicht zwei Werte, du sicherst nur, dass beide existieren, das ist etwas anderes.

3 Stimmen

Tatsächlich bewertet es auf die gleiche Weise wie JavaScript, von der Website: "Sie können den if-Helper verwenden, um einen Block bedingt zu rendern. Wenn das Argument falsch, undefined, null, "" oder [] (ein "falsy"-Wert) zurückgibt, wird Handlebars den Block nicht rendern."

1 Stimmen

Du hast recht, ich dachte zunächst, dass der Test dazu diente, zwei Werte zu vergleichen, nicht zu prüfen, ob beide existieren. Mein Fehler, Entschuldigung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X