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

479

Gibt es in Lenker JS eine Möglichkeit, logische Operatoren in den bedingten Operator standard handlebars.js zu integrieren? Etwas wie das:

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

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

Mike Robinson
quelle

Antworten:

518

Dies ist möglich durch "Schummeln" mit einem Blockhelfer. Dies widerspricht wahrscheinlich der Ideologie der Menschen, die Lenker entwickelt haben.

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

Sie können dann den Helfer in der Vorlage wie folgt aufrufen

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}
Nick Kitto
quelle
54
Dies widerspricht zwar der logischen Natur von Lenker / Schnurrbart, ist aber dennoch nützlich, danke!
Bala Clark
6
Beachten Sie, dass dies mit gebundenen Eigenschaften (Lesen, Ember-Bindungen) einfach nicht funktioniert. Es ist in Ordnung mit Literalwerten, löst jedoch keine Modelleigenschaften (getestet mit Ember 1.0.0-rc.8 und Handlebars 1.0.0) und registerBoundHelperkann nicht mit der Handlebars-Syntax umgehen. Die Problemumgehung besteht darin, eine benutzerdefinierte Ansicht zu erstellen: stackoverflow.com/questions/18005111/…
Warren Seine
28
@ BalaClark ist es wirklich logisch? Ich meine, es gibt immer noch "wenn" -Anweisungen - nur weil sie absichtlich verkrüppelt sind, ändert dies nichts an der Philosophie.
Phreakhead
111
Ich habe nie verstanden, warum Entwickler sich gerne selbst behindern.
StackOverflowed
36
Ich verstehe nicht, warum AND / OR nicht Teil des Lenkers sein kann. Es widerspricht nicht der logischen Natur, da es bereits IF, UNLESS und EACH gibt ... so viel zu logiklos
Asaf
445

Die Lösung noch einen Schritt weiter gehen. 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 dieser:

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

Kaffee-Skript-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
Jim
quelle
20
vergiss nicht '||'und '&&'. Ich habe diese Fälle hinzugefügt und sie sind sehr nützlich.
Jason
20
Als Noob am Lenker war nicht klar, dass Sie den Operator als Zeichenfolge übergeben müssen, da sonst der Compiler beim Tokenisieren Ihrer Vorlage einen Fehler macht. {{#ifCond true '==' false}}
Joe Holloway
2
Ich habe festgestellt, dass die Werte für Objektattribute nicht ausgewertet werden. Das Hinzufügen der folgenden Hilfen v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ZX12R
4
aber wenn v1 und v2 auch eine bedingung sind, wie kann ich sie dann verwenden? Zum Beispiel: if (Wert == "a" || Wert == "b")
Krishna
3
Kannst du ein anderes machen, wenn damit?
22.
160

Der Lenker unterstützt verschachtelte Vorgänge. Dies bietet viel Flexibilität (und saubereren Code), wenn wir unsere Logik etwas anders schreiben.

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

In der Tat können wir alle Arten von Logik hinzufügen:

{{#if (or 
        (eq section1 "foo")
        (ne section2 "bar"))}}
.. content
{{/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);
    }
});
kevlened
quelle
5
Beachten Sie, dass dies erst mit HTMLBars in Ember 1.10 möglich war. Diese Helfer werden auch als Ember-CLI-Addon geliefert, wenn Sie lieber: github.com/jmurphyau/ember-truth-helpers .
stephen.hanson
1
Auf diese Weise optionsist es besser , ohne Ausführung die ifMethode beizubehalten und einfacher zu testen. Vielen Dank!
Washington Botelho
25
Wir scheinen Lisp in den Lenker eingebaut zu haben.
Jdunning
8
Ihre andund orHelfer arbeiten nur mit 2 Parametern, was nicht das ist, was Sie wollen. Ich habe es geschafft, sowohl die andals auch die orHelfer zu überarbeiten , um mehr als zwei Parameter zu unterstützen. Verwenden Sie diesen Einzeiler für and: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);und verwenden Sie diesen Einzeiler für or: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);.
Luke
3
Eine etwas fortgeschrittenere Version , die für jeden Bediener mehrere Parameter annehmen kann.
Nate
87

Nehmen Sie dieses eine Stufe höher für diejenigen von Ihnen, die am Rande leben.

Kern : https://gist.github.com/akhoury/9118682 Demo : Code-Snippet unten

Lenker Helfer: {{#xif EXPRESSION}} {{else}} {{/xif}}

ein Helfer zum Ausführen einer IF-Anweisung mit einem beliebigen Ausdruck

  1. EXPRESSION ist ein ordnungsgemäß maskierter String
  2. Ja, Sie MÜSSEN den Zeichenfolgenliteralen ordnungsgemäß entkommen oder einfach einfache und doppelte Anführungszeichen wechseln
  3. Sie können auf jede globale Funktion oder Eigenschaft zugreifen, z encodeURIComponent(property)
  4. In diesem Beispiel wird vorausgesetzt , dass Sie diesen Zusammenhang am Lenker zu übergeben template( {name: 'Sam', age: '20' } ), Ankündigung ageist ein string, für nur so ich Demo kann parseInt()später in diesem Beitrag

Verwendungszweck:

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

Ausgabe

<p>
  BOOM
</p>

JavaScript: (es hängt von einem anderen Helfer ab - lesen Sie weiter)

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

Lenker Helfer: {{x EXPRESSION}}

Ein Helfer zum Ausführen von Javascript-Ausdrücken

  1. EXPRESSION ist ein ordnungsgemäß maskierter String
  2. Ja, Sie MÜSSEN den Zeichenfolgenliteralen ordnungsgemäß entkommen oder einfach einfache und doppelte Anführungszeichen wechseln
  3. Sie können auf jede globale Funktion oder Eigenschaft zugreifen, z parseInt(property)
  4. In diesem Beispiel wird davon ausgegangen template( {name: 'Sam', age: '20' } ), dass Sie diesen Kontext an Ihren Lenker übergeben haben. Dies ageist ein stringDemo-Zweck. Es kann alles sein.

Verwendungszweck:

<p>Url: {{x "'hi' + name + ', ' + window.location.href + ' <---- this is your href,' + ' your Age is:' + parseInt(this.age, 10)"}}</p>

Ausgabe:

<p>Url: hi Sam, http://example.com <---- this is your href, your Age is: 20</p>

JavaScript:

Dies sieht etwas groß aus, da ich die Syntax erweitert und aus Gründen der Übersichtlichkeit fast jede Zeile kommentiert habe

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: '[email protected]'
}, {
  firstName: 'Sam',
  age: '18',
  email: '[email protected]'
}, {
  firstName: 'Perter',
  lastName: 'Smith',
  age: '25',
  email: '[email protected]'
}];

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;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0/handlebars.min.js"></script>

<script id="template" type="text/x-handlebars-template">
  <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}} Please go back when you grow up. {{/xif}}
    </div>
    {{/each}}
  </div>
</script>

<div id="main"></div>

Moar

Wenn Sie auf den Bereich der oberen Ebene zugreifen möchten, unterscheidet sich dieser geringfügig. Der Ausdruck ist die VERBINDUNG aller Argumente. Verwendung: Sagen Sie, Kontextdaten sehen folgendermaßen aus:

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

// in template
// notice how the expression wrap all the string with quotes, and even the variables
// as they will become strings by the time they hit the helper
// play with it, you will immediately see the errored expressions and figure it out

{{#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);
});
Bentael
quelle
15
Das ist toll. Lenker können Ihnen nicht sagen, was zu tun ist :)
Lemiant
1
:) Danke, ich habe das Wesentliche ein wenig aktualisiert , um ein paar weitere Extras hinzuzufügen (nicht direkt im Zusammenhang mit dieser SO-Frage - aber im Geiste, das zu tun, was Sie in einer Lenkervorlage wollen). Sie sollten jedoch auf die Einschränkungen achten, die ich habe {{#each}} ... {{xif ' ../name === this.name' }} {{/each}}Ich habe keinen Weg gefunden, aus dem Ausdruck heraus auf "obere Bereichsebenen" zuzugreifen. Sagen wir, Sie befinden sich in jedem Bereich, ... aber ich untersuche immer noch ...
Bentael
1
fand eine Lösung für "Upper Scope Access", aber mit einem neuen Helfer, siehe aktualisierte Antwort, {{z ...}}Helfer
Bentael
BOOM ! Genial, jetzt kann ich in meinem teilweisen Dank echte Kondition machen !
AncAinu
1
@rickysullivan versuchen Sie, eval(expression);dies durch Folgendes zu ersetzen : eval('(function(){try{return ' + expression + ';}catch(e){}})();');- Ich weiß, dass dies hässlich wird, kann mir aber keinen sicheren Weg vorstellen , dies zu tun. - Bitte beachten Sie, dass dies nicht sehr "schnell" auszuführen ist. Ich würde dies nicht tun große Iteration.
Bentael
33

Es gibt eine einfache Möglichkeit, dies zu tun, ohne eine Hilfsfunktion zu schreiben ... Dies kann vollständig innerhalb der Vorlage erfolgen.

{{#if cond1}}   
  {{#if con2}}   
    <div> and condition completed</div>  
  {{/if}}
{{else}}   
  <div> both conditions weren't true</div>  
{{/if}}

Bearbeiten: Umgekehrt können Sie dies tun oder tun:

{{#if cond1}}  
  <div> or condition completed</div>    
{{else}}   
  {{#if cond2}}  
    <div> or condition completed</div>  
  {{else}}      
    <div> neither of the conditions were true</div>    
  {{/if}}  
{{/if}}

Bearbeiten / Hinweis: Auf der Website des Lenkers: handlebarsjs.com sind hier die falschen Werte:

Mit dem if-Helfer können Sie einen Block bedingt rendern. Wenn sein Argument false, undefined, null, "" oder [] (ein "falsy" -Wert) zurückgibt, wird jede 'cond' (wie cond1 oder cond2) nicht als true gezählt.

Jono
quelle
9
Nicht wirklich, Sie vergleichen nicht zwei Werte, Sie stellen nur sicher, dass beide existieren, es ist unterschiedlich.
Cyril N.
3
Tatsächlich wertet es es genauso aus wie Javascript auf der Website: "Sie können den if-Helfer verwenden, um einen Block bedingt zu rendern. Wenn sein Argument false, undefined, null," "oder [] (ein" falsy "-Wert) zurückgibt, Lenker rendern den Block nicht. "
Jono
1
Sie haben Recht, ich dachte zunächst, der Test sollte zwei Werte vergleichen, nicht beide. Es tut mir leid.
Cyril N.
4
Das funktioniert nicht richtig. Wenn cond1 wahr und con2 falsch ist, wird nichts gedruckt.
Tessa Lau
1
Hey @TessaLau, ich glaube ich sehe woher du kommst. Wenn Sie jedoch einen Kontrollfluss zeichnen, werden Sie feststellen, dass der Kontrollfluss in der ersten Zeile in diesen Zustand versetzt wird.
Jono
19

Ein Problem bei allen hier veröffentlichten Antworten besteht darin, dass sie nicht mit gebundenen Eigenschaften funktionieren, dh die if-Bedingung wird nicht neu bewertet, wenn sich die beteiligten Eigenschaften ändern. Hier ist eine etwas fortgeschrittenere Version des Helfers, der Bindungen unterstützt. Es verwendet die Bindefunktion aus der Ember-Quelle, mit der auch der normale Ember- #ifHelfer implementiert wird .

Diese ist auf eine einzelne gebundene Eigenschaft auf der linken Seite beschränkt, verglichen mit einer Konstante auf der rechten Seite, die meiner Meinung nach für die meisten praktischen Zwecke gut genug ist. Wenn Sie etwas Fortgeschritteneres als einen einfachen Vergleich benötigen, ist es vielleicht gut, einige berechnete Eigenschaften zu deklarieren und stattdessen den normalen #ifHelfer zu verwenden.

Ember.Handlebars.registerHelper('ifeq', function(a, b, options) {
  return Ember.Handlebars.bind.call(options.contexts[0], a, options, true, function(result) {
    return result === b;
  });
});

Sie können es so verwenden:

{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}
Devongovett
quelle
Dies ist die richtige Antwort, wenn Sie Ember verwenden. Die anderen Lösungen, wie Sie erwähnt haben, übergeben nur den Schlüssel anstelle des Werts. Übrigens, danke dafür, habe ein paar Stunden damit verbracht, mir den Kopf zu zerbrechen.
J Lee
2
Hat jemand dies mit HTMLBars / Ember 1.10 zum Laufen gebracht? Ember.Handlebars.bind scheint nicht mehr zu existieren.
Linda
Ich habe ursprünglich registerBoundHelper ursprünglich verwendet, aber wenn es den Zustand änderte, änderte es sich nicht in den else-Wert und zurück. Diese Methode funktioniert mit Glut zum Ändern :) Es sollte viel mehr Stimmen haben
Matt Vukomanovic
13

Verbesserte Lösung, die grundsätzlich mit jedem Binäroperator funktioniert (zumindest Zahlen, Zeichenfolgen funktionieren mit eval nicht gut. Achten Sie auf eine mögliche SCRIPT-Injektion, wenn Sie einen nicht definierten Operator mit Benutzereingaben verwenden):

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 eval(""+v1+operator+v2)?options.fn(this):options.inverse(this);
    }
});
Vincent
quelle
Wie würden Sie dies in einer Vorlage verwenden? vor allem die options.fn teil?
Qodeninja
{{ifCond val1 '||' val2}} true {{else}} false {{/ if}} gibt options.fn (true, die ifCond-Klausel) zurück, wenn es korrekt ist, andernfalls gibt es options.inverse (false, die else-Klausel) zurück, wenn es falsch ist.
Nick Kitto
1
Aufgrund der Vorbehalte bezüglich der Skriptinjektion würde ich dringend empfehlen, diesen Helfer nicht zu verwenden. In einer großen Codebasis könnte dies leicht für ein böses Sicherheitsproblem auf der
ganzen
8

Hier ist eine Lösung, wenn Sie mehrere Bedingungen überprüfen möchten:

/* Handler to check multiple conditions
   */
  Handlebars.registerHelper('checkIf', function (v1,o1,v2,mainOperator,v3,o2,v4,options) {
      var operators = {
           '==': function(a, b){ return a==b},
           '===': function(a, b){ return a===b},
           '!=': function(a, b){ return a!=b},
           '!==': function(a, b){ return a!==b},
           '<': function(a, b){ return a<b},
           '<=': function(a, b){ return a<=b},
           '>': function(a, b){ return a>b},
           '>=': function(a, b){ return a>=b},
           '&&': function(a, b){ return a&&b},
           '||': function(a, b){ return a||b},
        }
      var a1 = operators[o1](v1,v2);
      var a2 = operators[o2](v3,v4);
      var isTrue = operators[mainOperator](a1, a2);
      return isTrue ? options.fn(this) : options.inverse(this);
  });

Verwendungszweck:

/* if(list.length>0 && public){}*/

{{#checkIf list.length '>' 0 '&&' public '==' true}} <p>condition satisfied</p>{{/checkIf}}
Sateesh Kumar Alli
quelle
7

Hier ist ein Link zu dem Blockhelfer, den ich benutze: Vergleichsblockhelfer . Es unterstützt alle Standardoperatoren und ermöglicht das Schreiben von Code wie unten gezeigt. Es ist wirklich sehr praktisch.

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
CleanTheRuck
quelle
1
Dies sollte die Siegerabstimmung sein. Einheimisch und beabsichtigt. Ich finde fast jedes Mal, wenn Sie einen neuen Helfer schreiben, überdenken Sie ihn.
Augurone
2
@augurone das ist kein einheimischer Helfer. Wenn Sie dem Link folgen, sehen Sie, dass es sich um einen benutzerdefinierten Helfer handelt.
Gfullam
@gfullam Sie haben Recht, ich habe Lenker in der Montage verwendet, die diesen Helfer nativ enthält. Mein Fehler.
Augurone
4

Ähnlich wie bei Jims Antwort, aber mit ein wenig Kreativität könnten wir auch so etwas tun:

Handlebars.registerHelper( "compare", function( v1, op, v2, options ) {

  var c = {
    "eq": function( v1, v2 ) {
      return v1 == v2;
    },
    "neq": function( v1, v2 ) {
      return v1 != v2;
    },
    ...
  }

  if( Object.prototype.hasOwnProperty.call( c, op ) ) {
    return c[ op ].call( this, v1, v2 ) ? options.fn( this ) : options.inverse( this );
  }
  return options.inverse( this );
} );

Um es dann zu benutzen, bekommen wir so etwas wie:

{{#compare numberone "eq" numbretwo}}
  do something
{{else}}
  do something else
{{/compare}}

Ich würde vorschlagen, das Objekt aus der Funktion zu entfernen, um eine bessere Leistung zu erzielen. Andernfalls können Sie jede gewünschte Vergleichsfunktion hinzufügen, einschließlich "und" und "oder".

ars265
quelle
3

Eine andere Alternative ist die Verwendung des Funktionsnamens in #if. Der #iferkennt, ob der Parameter eine Funktion ist, und wenn dies der Fall ist, ruft er ihn auf und verwendet seine Rückgabe zur Überprüfung der Richtigkeit. Unter myFunction wird der aktuelle Kontext als angezeigt this.

{{#if myFunction}}
  I'm Happy!
{{/if}}
Shital Shah
quelle
Sie müssten also eine Funktion in den Kontext einfügen? Das Ausführen von Code aus einem Kontext ist eine Sicherheitslücke, da die Quelle des Codes unbekannt sein kann. Dies kann für einen XSS-Angriff ausgenutzt werden.
T Nguyen
Ja, Sie müssen dem Kontext eine Funktion hinzufügen. In einer schlecht gestalteten Website könnte dies eine Sicherheitslücke sein. Aber in diesem Fall würde es viele andere geben.
Shital Shah
Dies ist der bevorzugte Weg. TY.
elad.chen
3

Leider löst keine dieser Lösungen das Problem des "ODER" -Operators "cond1 || cond2".

  1. Überprüfen Sie, ob der erste Wert wahr ist
  2. Verwenden Sie "^" (oder) und prüfen Sie, ob ansonsten cond2 wahr ist

    {{#if cond1}} TUN SIE DIE AKTION {{^}} {{#if cond2}} TUN SIE DIE AKTION {{/ if}} {{/ if}}

Es verstößt gegen die DRY-Regel. Warum also nicht teilweise verwenden, um es weniger chaotisch zu machen?

{{#if cond1}}
    {{> subTemplate}}
{{^}}
    {{#if cond2}}
        {{> subTemplate}}
    {{/if}}
{{/if}}
Pawel
quelle
3

Ich kann verstehen, warum Sie einen Helfer für Situationen erstellen möchten, in denen Sie eine große Anzahl unterschiedlicher Vergleiche innerhalb Ihrer Vorlage durchführen müssen, aber für eine relativ kleine Anzahl von Vergleichen (oder sogar einen, was mich auf diese Seite gebracht hat) Erstens wäre es wahrscheinlich einfacher, eine neue Lenkervariable in Ihrem Funktionsaufruf zum Rendern von Ansichten zu definieren, z.

Beim Rendern an den Lenker übergeben:

var context= {
    'section1' : section1,
    'section2' : section2,
    'section1or2' : (section1)||(section2)
};

und dann in Ihrer Lenkervorlage:

{{#if section1or2}}
    .. content
{{/if}}

Ich erwähne dies der Einfachheit halber und auch, weil es eine Antwort ist, die schnell und hilfreich sein kann, während die logische Natur von Lenkern eingehalten wird.

Programmierer Dan
quelle
3

Installieren Sie das Ember Truth Helpers- Addon, indem Sie den folgenden Befehl ausführen

Glut installieren Glut-Wahrheit-Helfer

Sie können die meisten logischen Operatoren verwenden (eq, not-eq, not und oder oder gt, gte, lt, lte, xor).

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

Sie können sogar einen Unterausdruck einfügen, um weiter zu gehen.

{{#if (or (eq section1 "section1") (eq section2 "section2") ) }}  
...content  
{{/if}}
Ember Freak
quelle
2

Noch eine krumme Lösung für einen ternären Helfer:

'?:' ( condition, first, second ) {
  return condition ? first : second;
}

<span>{{?: fooExists 'found it' 'nope, sorry'}}</span>

Oder ein einfacher Koaleszenzhelfer:

'??' ( first, second ) {
  return first ? first : second;
}

<span>{{?? foo bar}}</span>

Da diese Zeichen im Lenker-Markup keine besondere Bedeutung haben, können Sie sie für Hilfsnamen verwenden.

Moritz Friedrich
quelle
1

Ich habe ein mit CoffeeScript erstelltes npm-Paket gefunden, das viele unglaublich nützliche Helfer für Lenker enthält. Schauen Sie sich die Dokumentation unter der folgenden URL an:

https://npmjs.org/package/handlebars-helpers

Sie können eine tun wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgz herunterladen und den Inhalt des Pakets anzeigen.

Sie werden in der Lage sein, Dinge wie {{#is number 5}}oder zu tun{{formatDate date "%m/%d/%Y"}}

Cristian Rojas
quelle
1

Wenn Sie nur überprüfen möchten, ob das eine oder andere Element vorhanden ist, können Sie diesen benutzerdefinierten Helfer verwenden

Handlebars.registerHelper('if_or', function(elem1, elem2, options) {
  if (Handlebars.Utils.isEmpty(elem1) && Handlebars.Utils.isEmpty(elem2)) {
    return options.inverse(this);
  } else {
    return options.fn(this);
  }
});

so was

{{#if_or elem1 elem2}}
  {{elem1}} or {{elem2}} are present
{{else}}
  not present
{{/if_or}}

wenn Sie auch ein "oder" benötigen, um Funktionsrückgabewerte zu vergleichen möchte ich lieber eine weitere Eigenschaft hinzufügen, die das gewünschte Ergebnis zurückgibt.

Die Vorlagen sollten doch logisch sein!

tiefe Flamme
quelle
1

Ich bin gerade von einer Google-Suche zu diesem Beitrag gekommen, um zu überprüfen, ob eine Zeichenfolge einer anderen Zeichenfolge entspricht.

Ich verwende HandlebarsJS auf der NodeJS-Serverseite, aber ich verwende auch dieselben Vorlagendateien im Front-End, indem ich die Browserversion von HandlebarsJS verwende, um sie zu analysieren. Das bedeutete, wenn ich einen benutzerdefinierten Helfer haben wollte, musste ich ihn an zwei verschiedenen Stellen definieren oder dem betreffenden Objekt eine Funktion zuweisen - zu viel Aufwand !!

Was die Leute vergessen, ist, dass bestimmte Objekte Vererbungsfunktionen haben, die in der Schnurrbartvorlage verwendet werden können. Im Fall einer Zeichenfolge:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match

An Array containing the entire match result and any parentheses-captured matched results; null if there were no matches.

Wir können diese Methode verwenden, um entweder ein Array von Übereinstimmungen zurückzugeben oder nullwenn keine Übereinstimmungen gefunden wurden. Dies ist perfekt, da Sie sich die Dokumentation zu HandlebarsJS unter http://handlebarsjs.com/builtin_helpers.html ansehen

You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], Handlebars will not render the block.

Damit...

{{#if your_string.match "what_youre_looking_for"}} 
String found :)
{{else}}
No match found :(
{{/if}}

AKTUALISIEREN:

Nach dem Testen in allen Browsern funktioniert dies unter Firefox nicht . HandlebarsJS übergibt andere Argumente an einen Funktionsaufruf. Wenn also String.prototype.match aufgerufen wird, scheint das zweite Argument (dh die Regexp-Flags für den Aufruf der Übereinstimmungsfunktion gemäß obiger Dokumentation) übergeben zu werden. Firefox sieht dies als veraltete Verwendung von String.prototype.match an und bricht daher ab.

Eine Problemumgehung besteht darin, einen neuen funktionalen Prototyp für das String JS-Objekt zu deklarieren und stattdessen Folgendes zu verwenden:

if(typeof String.includes !== 'function') {
    String.prototype.includes = function(str) {
        if(!(str instanceof RegExp))
            str = new RegExp((str+'').escapeRegExp(),'g');
        return str.test(this);
    }
}

Stellen Sie sicher, dass dieser JS-Code enthalten ist, bevor Sie die Funktion Handlebars.compile () und dann in Ihrer Vorlage ausführen ...

{{#your_string}}
    {{#if (includes "what_youre_looking_for")}} 
        String found :)
    {{else}}
        No match found :(
    {{/if}}
{{/your_string}}
Jon
quelle
Für Firefox aktualisiert, ist dies, was ich derzeit verwende
Jon
1

Hier haben wir Vanille-Lenker für mehrere logische && und || (und oder):

Handlebars.registerHelper("and",function() {
    var args = Array.prototype.slice.call(arguments);
    var options = args[args.length-1];

    for(var i=0; i<args.length-1; i++){
        if( !args[i] ){
            return options.inverse(this);
        }
    }

    return options.fn(this);
});


Handlebars.registerHelper("or",function() {
    var args = Array.prototype.slice.call(arguments);
    var options = args[args.length-1];

    for(var i=0; i<args.length-1; i++){
        if( args[i] ){
            return options.fn(this);
        }
    }

    return options.inverse(this);
}

// Results
// {{#and foo bar sally bob}} yup {{else}} nope {{/and}} // yup
// {{#or foo bar "" sally bob}} yup {{else}} nope {{/or}} // yup

// {{#and foo bar "" sally bob}} yup {{else}} nope {{/and}} // nope
// {{#or "" "" "" "" ""}} yup {{else}} nope {{/or}} // nope

Nicht so sicher, ob es "sicher" ist, "und" und "oder" zu verwenden ... vielleicht zu etwas wie "op_and" und "op_or" wechseln?

Bob
quelle
1

Richtige Lösung für UND / ODER

Handlebars.registerHelper('and', function () {
    // Get function args and remove last one (function name)
    return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);
});
Handlebars.registerHelper('or', function () {
    // Get function args and remove last one (function name)
    return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);
}); 

Rufen Sie dann wie folgt an

{{#if (or (eq questionType 'STARTTIME') (eq questionType 'ENDTIME') (..) ) }}

Übrigens: Beachten Sie, dass die hier angegebene Lösung falsch ist. Er subtrahiert nicht das letzte Argument, das der Funktionsname ist. https://stackoverflow.com/a/31632215/1005607

Sein ursprüngliches UND / ODER basierte auf der vollständigen Liste der Argumente

   and: function () {
        return Array.prototype.slice.call(arguments).every(Boolean);
    },
    or: function () {
        return Array.prototype.slice.call(arguments).some(Boolean);
    }

Kann jemand diese Antwort ändern? Ich habe gerade eine Stunde damit verbracht, etwas in einer von 86 Leuten empfohlenen Antwort zu reparieren. Die Lösung besteht darin , das letzte Argument herauszufiltern, bei dem es sich um den Funktionsnamen handelt.Array.prototype.slice.call(arguments, 0, arguments.length - 1)

Gen b.
quelle
0

Nach diesen beiden Anleitungen , mit denen Benutzer benutzerdefinierte gebundene if-Anweisungen und benutzerdefinierte gebundene Helfer definieren können, konnte ich meine freigegebenen Ansichten in diesem Beitrag zum Stapelüberlauf anpassen , um diese anstelle des Standard-# zu verwenden if-Anweisung. Dies sollte sicherer sein, als nur ein #if hineinzuwerfen.

Die benutzerdefinierten Helfer in diesem Kern sind hervorragend.

<li>
    <a href="{{unbound view.varProductSocialBlog}}">
        {{#if-equal view.showDiv "true"}}<div>{{/if-equal}}<i class="fa fa-rss-square"></i>{{#if-equal view.showDiv "true"}}</div>{{/if-equal}}
        {{#if-equal view.showTitle "true"}}Blog{{/if-equal}}
    </a>
</li>

Ich benutze die Glut Cli Projekt, um meine Ember-Anwendung zu erstellen.

Aktuelles Setup zum Zeitpunkt dieses Beitrags:

DEBUG: -------------------------------
DEBUG: Ember      : 1.5.1
DEBUG: Ember Data : 1.0.0-beta.7+canary.b45e23ba
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery     : 2.1.1
DEBUG: -------------------------------
Chris Hough
quelle
0

In Ember.js können Sie inline if helper in if block helper verwenden. Es kann den ||logischen Operator ersetzen , zum Beispiel:

{{#if (if firstCondition firstCondition secondCondition)}}
  (firstCondition || (or) secondCondition) === true
{{/if}}
Daniel Kmak
quelle
0

Sie können dies einfach tun, indem Sie den folgenden logischen Operator verwenden:

{{#if (or(eq firstValue 'String_to_compare_value') (eq secondValue 'String_to_compare_value'))}}business logic goes here{{/if}}

{{#if (and(eq firstValue 'String_to_compare_value') (eq secondValue 'String_to_compare_value'))}}business logic goes here{{/if}}

Vor dem Schließen, wenn Sie Ihre Geschäftslogik schreiben können

Kunwar Babu
quelle
0

Sie können den folgenden Code verwenden:

{{#if selection1}}
    doSomething1
{{else}}
   {{#if selection2}}
       doSomething2
   {{/if}}
{{/if}}
varuni
quelle
Bitte erläutern Sie mehr über Ihre Gedanken und Prozesse. Es kann für Menschen sehr schwierig sein, Ihre Lösung zu verstehen, wenn sie den Kontext nicht kennen oder neu in der Sprache sind.
Mrhn
-1

Hier ist ein Ansatz, den ich für Ember 1.10 und Ember-Cli 2.0 verwende.

// app/helpers/js-x.js
export default Ember.HTMLBars.makeBoundHelper(function (params) {
  var paramNames = params.slice(1).map(function(val, idx) { return "p" + idx; });
  var func = Function.apply(this, paramNames.concat("return " + params[0] + ";"))
  return func.apply(params[1] === undefined ? this : params[1], params.slice(1));
});

Dann können Sie es in Ihren Vorlagen wie folgt verwenden:

// used as sub-expression
{{#each item in model}}
  {{#if (js-x "this.section1 || this.section2" item)}}
  {{/if}}
{{/each}}

// used normally
{{js-x "p0 || p1" model.name model.offer.name}}

Wo die Argumente für den Ausdruck übergeben werden in wie p0, p1, p2usw. und p0kann auch als Bezug genommen werden this.

Michael
quelle