Operatore logico in un condizionale handlebars.js {{#if}}


479

Esiste un modo nel manubrio JS di incorporare operatori logici nell'operatore condizionale handlebars.js standard? Qualcosa come questo:

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

So di poter scrivere il mio aiutante, ma prima vorrei assicurarmi di non reinventare la ruota.

Risposte:


519

Ciò è possibile "ingannando" con un aiutante di blocco. Questo probabilmente va contro l'ideologia delle persone che hanno sviluppato il manubrio.

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

È quindi possibile chiamare l'helper nel modello in questo modo

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}

54
Questo va contro la natura senza logica di Manubri / Baffi, ma è sicuramente utile, grazie!
Bala Clark,

6
Nota che questo semplicemente non funziona con le proprietà associate (leggi, collegamenti Ember). Va bene con i valori letterali, ma non risolve le proprietà del modello (testato con Ember 1.0.0-rc.8 e Handlebars 1.0.0) e registerBoundHelpernon può gestire la sintassi di Handlebars. Per risolvere il problema, creare una vista personalizzata: stackoverflow.com/questions/18005111/…
Warren Seine,

28
@BalaClark è davvero senza logica? Voglio dire che ha ancora dichiarazioni "if" - solo perché sono intenzionalmente paralizzate non cambia la filosofia.
phreakhead,

111
Non ho mai capito perché agli sviluppatori piaccia handicap.
StackOverflow

36
Non capisco perché AND / OR non possa far parte del manubrio. Non va contro la natura senza logica poiché ci sono già SE, SENZA MENO e OGNI ... così tanto per senza logica
Asaf

445

Portare la soluzione un passo avanti. Questo aggiunge l'operatore di confronto.

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);
    }
});

Usalo in un modello come questo:

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

Versione Coffee Script

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

20
non dimenticare di '||'e '&&'. Ho aggiunto questi casi e sono molto utili.
Jason,

20
Essendo un noob per il manubrio una cosa che non era chiara è che devi passare l'operatore come una stringa, altrimenti il ​​compilatore sbaglierà mentre tokenizza il tuo modello. {{#ifCond true '==' false}}
Joe Holloway l'

2
Ho trovato i valori da non valutare per gli attributi degli oggetti. L'aggiunta di quanto segue aiuta v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ZX12R

4
ma se v1 e v2 anche una condizione, allora come posso usare? ad esempio: if (valore == "a" || valore == "b")
Krishna

3
Puoi fare un altro se con questo?
jbyrd,

160

Il manubrio supporta le operazioni nidificate. Ciò fornisce molta flessibilità (e un codice più pulito) se scriviamo la nostra logica in modo leggermente diverso.

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

In effetti, possiamo aggiungere ogni tipo di logica:

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

Basta registrare questi helper:

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
Nota che questo non era possibile fino a HTMLBars in Ember 1.10. Inoltre, questi aiutanti vengono come addon della CLI di Ember se preferisci: github.com/jmurphyau/ember-truth-helpers .
stephen.hanson,

1
In questo modo, senza optionsesecuzione è meglio attenersi al ifmetodo e più facile da testare. Grazie!
Washington Botelho,

25
Sembra che abbiamo incorporato Lisp nel manubrio.
jdunning,

8
Your ande orhelpers funzionano solo con 2 parametri, che non è quello che desideri. Sono riuscito a rielaborare entrambi gli helper ande orper supportare più di due parametri. Utilizzare questa one-liner per and: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);e utilizzare questa one-liner per or: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);.
Luca,

3
Una versione un po 'più avanzata che può accettare più parametri su ciascun operatore.
Nate,

87

portando questo su un gradino, per quelli di voi che vivono ai margini.

gist : https://gist.github.com/akhoury/9118682 Demo : frammento di codice di seguito

Supporto manubrio: {{#xif EXPRESSION}} {{else}} {{/xif}}

un aiutante per eseguire un'istruzione IF con qualsiasi espressione

  1. EXPRESSION è una stringa con escape corretto
  2. Sì, è NECESSARIO sfuggire correttamente ai valori letterali delle stringhe o semplicemente alternare virgolette singole e doppie
  3. puoi accedere a qualsiasi funzione o proprietà globale, ad es encodeURIComponent(property)
  4. questo esempio presuppone che tu abbia passato questo contesto al tuo manubrio template( {name: 'Sam', age: '20' } ), notare che ageè un string, solo per così posso dimostrarlo parseInt()più avanti in questo post

Uso:

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

Produzione

<p>
  BOOM
</p>

JavaScript: (dipende da un altro aiutante, continua a leggere)

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

Supporto manubrio: {{x EXPRESSION}}

Un aiuto per eseguire espressioni javascript

  1. EXPRESSION è una stringa con escape corretto
  2. Sì, è NECESSARIO sfuggire correttamente ai valori letterali delle stringhe o semplicemente alternare virgolette singole e doppie
  3. puoi accedere a qualsiasi funzione o proprietà globale, ad es parseInt(property)
  4. questo esempio presuppone che tu abbia passato questo contesto al tuo manubrio template( {name: 'Sam', age: '20' } ), ageè a stringscopo dimostrativo, può essere qualsiasi cosa ..

Uso:

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

Produzione:

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

JavaScript:

Questo sembra un po 'grande perché ho ampliato la sintassi e commentato quasi ogni riga per motivi di chiarezza

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;
}
<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

se si desidera accedere all'ambito di livello superiore, questo è leggermente diverso, l'espressione è la JOIN di tutti gli argomenti, utilizzo: dire che i dati di contesto si presentano così:

// 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);
});

15
Questo è fantastico Il manubrio non può dirti cosa fare :)
lemiant

1
:) grazie, ho aggiornato un po ' l' essenza per aggiungere alcune altre chicche (non direttamente correlate a questa domanda SO - ma nello spirito di fare quello che vuoi all'interno di un modello di manubrio) Tuttavia, dovresti fare attenzione alle limitazioni, non ho {{#each}} ... {{xif ' ../name === this.name' }} {{/each}}ho trovato un modo per accedere ai "livelli di ambito superiore" dall'interno dell'espressione, diciamo che sei in ogni ambito, ... ma sto ancora studiando ...
bentael

1
ha trovato una soluzione per "accesso all'ambito superiore" ma utilizzando un nuovo helper, vedere la risposta aggiornata, {{z ...}}helper
bentael

BOOM! Fantastico, ora posso fare delle vere condizioni nel mio parziale ringraziamento!
AncAinu,

1
@rickysullivan prova a sostituire il tuo eval(expression);con questo: eval('(function(){try{return ' + expression + ';}catch(e){}})();');- So che sta diventando brutto, ma non riesco a pensare a un modo sicuro per farlo - Tieni presente che non è molto "veloce" da eseguire, non lo farei in iterazione enorme.
bentael,

33

C'è un modo semplice per farlo senza scrivere una funzione di supporto ... Può essere fatto completamente all'interno del modello.

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

Modifica: al contrario puoi fare o facendo così:

{{#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}}

Modifica / Nota: dal sito Web del manubrio: handlebarsjs.com ecco i valori falsi:

È possibile utilizzare l'helper if per eseguire il rendering condizionale di un blocco. Se il suo argomento restituisce false, undefined, null, "" o [] (un valore "falsy"), qualsiasi 'cond' (come cond1 o cond2) non verrà conteggiato come vero.


9
Non proprio, non confronti due valori, ti assicuri solo che esistono entrambi, è diverso.
Cirillo N.

3
In realtà lo valuta allo stesso modo di JavaScript, dal sito Web: "È possibile utilizzare l'helper if per eseguire il rendering condizionale di un blocco. Se il suo argomento restituisce false, indefinito, null" "o [] (un valore" falsy "), Il manubrio non renderà il blocco ".
Jono,

1
Hai ragione, in primo luogo ho pensato che il test fosse quello di confrontare due valori, non i test di entrambi esistevano. Mio male, scusa.
Cyril N.

4
Questo non funziona correttamente. Se cond1 è vero e con2 è falso, non verrà stampato nulla.
Tessa Lau,

1
Ehi @TessaLau, penso di vedere da dove vieni. Tuttavia, se si disegna un flusso di controllo, si vedrà che nella prima riga si sposta il flusso di controllo in quella condizione.
Jono

19

Un problema con tutte le risposte pubblicate qui è che non funzionano con le proprietà associate, ovvero la condizione if non viene rivalutata quando cambiano le proprietà coinvolte. Ecco una versione leggermente più avanzata dell'helper che supporta i binding. Esso utilizza la legano funzione dalla fonte Ember, che è anche utilizzato per implementare la normale Ember #ifaiutante.

Questo è limitato a una singola proprietà associata sul lato sinistro, rispetto a una costante sul lato destro, che penso sia abbastanza buona per la maggior parte degli scopi pratici. Se hai bisogno di qualcosa di più avanzato di un semplice confronto, allora forse sarebbe bene iniziare a dichiarare alcune proprietà calcolate e utilizzare #ifinvece l'helper normale .

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

Puoi usarlo in questo modo:

{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}

Questa è la risposta appropriata se si utilizza Ember. Le altre soluzioni come hai menzionato passeranno semplicemente la chiave invece del valore. A proposito grazie per questo, ho trascorso alcune ore a farmi arrabbiare la testa.
J Lee,

2
Qualcuno ha ottenuto che funzioni con HTMLBars / Ember 1.10? Ember.Handlebars.bind non sembra più esistere.
Linda,

Inizialmente ho usato registerBoundHelper in origine, ma quando ha cambiato condizione non cambiava il valore else e viceversa. Questo metodo funziona con la brace per cambiare :) Dovrebbe avere molti più voti in alto
Matt Vukomanovic

13

Soluzione migliorata che funziona fondamentalmente con qualsiasi operatore binario (almeno numeri, stringhe non funzionano bene con eval, PRENDITI CURA DI POSSIBILE INIEZIONE DI SCRIPT SE UTILIZZA UN OPERATORE NON DEFINITO CON INGRESSI UTENTE):

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);
    }
});

come lo useresti in un modello? in particolare le opzioni. parte?
qodeninja,

{{ifCond val1 '||' val2}} true {{else}} false {{/ if}} restituisce options.fn (true, la clausola ifCond) se è corretta, altrimenti restituisce options.inverse (false, la clausola else) se errata.
Nick Kitto,

1
A causa delle avvertenze menzionate sull'iniezione di script, raccomanderei caldamente di non usare questo aiuto. In una grande base di codice questo potrebbe facilmente essere responsabile di un brutto problema di sicurezza lungo la linea
Jordan Sitkin,

8

Ecco una soluzione se si desidera verificare più condizioni:

/* 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);
  });

Uso:

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

{{#checkIf list.length '>' 0 '&&' public '==' true}} <p>condition satisfied</p>{{/checkIf}}

7

Ecco un link all'helper del blocco che uso: helper del blocco di confronto . Supporta tutti gli operatori standard e consente di scrivere codice come mostrato di seguito. È davvero molto utile.

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}

1
Questo dovrebbe essere il voto vincente. Nativo e previsto. Trovo quasi ogni volta che se stai scrivendo un nuovo aiutante lo pensi troppo.
augurone,

2
@augurone questo non è un aiuto nativo. Se segui il link vedrai che si tratta di un aiuto personalizzato.
gfullam,

@gfullam hai ragione, stavo usando il manubrio in assemblare, che include nativamente questo aiutante. Colpa mia.
Augurone,

4

Simile alla risposta di Jim, ma usando un po 'di creatività potremmo anche fare qualcosa del genere:

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 );
} );

Quindi per usarlo otteniamo qualcosa di simile:

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

Suggerirei di spostare l'oggetto fuori dalla funzione per prestazioni migliori, ma in caso contrario puoi aggiungere qualsiasi funzione di confronto che desideri, inclusi "e" e "o".


3

Un'altra alternativa è utilizzare il nome della funzione in #if. Il #ifrileverà se il parametro è funzione e se è allora chiameremo e utilizzare il suo ritorno per il controllo truthyness. Sotto myFunction viene visualizzato il contesto corrente come this.

{{#if myFunction}}
  I'm Happy!
{{/if}}

Quindi avresti bisogno di aggiungere una funzione nel contesto? L'esecuzione di codice da un contesto è una falla di sicurezza, poiché la fonte del codice potrebbe essere sconosciuta. Questo può essere sfruttato per un attacco XSS.
T Nguyen,

Sì, è necessario aggiungere una funzione al contesto. In un sito Web mal progettato, sì, questo potrebbe essere un buco nella sicurezza. Ma in quel caso, ce ne sarebbero molti altri.
Shital Shah,

Questo è il modo preferito .. TY.
elad.chen,

3

Sfortunatamente nessuna di queste soluzioni risolve il problema dell'operatore "OR" cond1 || cond2 ".

  1. Controlla se il primo valore è vero
  2. Usa "^" (o) e controlla se cond2 è vero

    {{#if cond1}} ESEGUI L'AZIONE {{^}} {{#if cond2}} ESEGUI L'AZIONE {{/ if}} {{/ if}}

Si rompe la regola DRY. Quindi perché non usare il parziale per renderlo meno disordinato

{{#if cond1}}
    {{> subTemplate}}
{{^}}
    {{#if cond2}}
        {{> subTemplate}}
    {{/if}}
{{/if}}

3

Posso capire perché vorresti creare un aiuto per le situazioni in cui hai un gran numero di confronti vari da eseguire all'interno del tuo modello, ma per un numero relativamente piccolo di confronti (o anche uno, che è stato ciò che mi ha portato a questa pagina in in primo luogo), sarebbe probabilmente più semplice definire una nuova variabile manubrio nella chiamata della funzione di rendering della vista, come:

Passa al manubrio sul rendering:

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

e quindi all'interno del modello del tuo manubrio:

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

Lo dico per semplicità, e anche perché è una risposta che può essere rapida e utile pur rispettando la natura senza logica del manubrio.


3

Installa il componente aggiuntivo Ember Truth Helpers eseguendo il comando seguente

ember installa ember-truth-helpers

puoi iniziare a usare la maggior parte degli operatori logici (eq, not-eq, not, e, o, gt, gte, lt, lte, xor).

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

Puoi anche includere la sottoespressione per andare oltre,

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

2

Ancora un'altra soluzione storta per un aiutante ternario:

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

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

O un semplice aiutante di coesione:

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

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

Poiché questi caratteri non hanno un significato speciale nel markup del manubrio, sei libero di usarli per i nomi degli helper.


1

Ho trovato un pacchetto npm realizzato con CoffeeScript che ha molti incredibili aiutanti utili per il manubrio. Dai un'occhiata alla documentazione nel seguente URL:

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

Puoi farlo wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgzper scaricarli e vedere il contenuto del pacchetto.

Sarai in grado di fare cose come {{#is number 5}}o{{formatDate date "%m/%d/%Y"}}


1

se vuoi solo controllare se sono presenti uno o l'altro elemento puoi usare questo helper personalizzato

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);
  }
});

come questo

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

se devi anche essere in grado di avere un "o" per confrontare i valori di ritorno della funzione , preferirei aggiungere un'altra proprietà che restituisca il risultato desiderato.

I modelli dovrebbero essere senza logica dopo tutto!



1

Sono appena arrivato a questo post da una ricerca su Google su come verificare se una stringa è uguale a un'altra stringa.

Uso HandlebarsJS nel lato server NodeJS, ma utilizzo anche gli stessi file modello sul front-end utilizzando la versione browser di HandlebarsJS per analizzarlo. Ciò significava che se avessi voluto un aiutante personalizzato, avrei dovuto definirlo in 2 posti separati o assegnare una funzione all'oggetto in questione - troppo sforzo !!

Ciò che la gente dimentica è che alcuni oggetti hanno funzioni ereditarie che possono essere utilizzate nel modello di baffi. Nel caso di una stringa:

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.

Possiamo usare questo metodo per restituire una matrice di corrispondenze o nullse non sono state trovate corrispondenze. Questo è perfetto, perché guardando la documentazione di HandlebarsJS http://handlebarsjs.com/builtin_helpers.html

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.

Così...

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

AGGIORNARE:

Dopo il test su tutti i browser, questo non funziona su Firefox . HandlebarsJS passa altri argomenti a una chiamata di funzione, il che significa che quando viene chiamato String.prototype.match, il secondo argomento (ovvero i flag Regexp per la chiamata della funzione di corrispondenza secondo la documentazione precedente) sembra essere passato. Firefox vede questo come un uso deprecato di String.prototype.match e quindi si interrompe.

Una soluzione alternativa è dichiarare un nuovo prototipo funzionale per l'oggetto String JS e utilizzarlo invece:

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

Assicurarsi che questo codice JS sia incluso prima di eseguire la funzione Handlebars.compile (), quindi nel modello ...

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

Aggiornato per Firefox, questo è quello che sto attualmente usando
Jon

1

Qui abbiamo il manubrio alla vaniglia per più logici && e || (e o):

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

Non sei così sicuro se è "sicuro" usare "e" e "o" ... forse cambia in qualcosa come "op_and" e "op_or"?


1

Soluzione corretta per AND / OR

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);
}); 

Quindi chiamare come segue

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

BTW: Nota che la soluzione fornita qui non è corretta, non sta sottraendo l'ultimo argomento che è il nome della funzione. https://stackoverflow.com/a/31632215/1005607

Il suo AND / OR originale era basato sull'elenco completo degli argomenti

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

Qualcuno può cambiare quella risposta? Ho appena perso un'ora cercando di risolvere qualcosa in una risposta raccomandata da 86 persone. La correzione consiste nel filtrare l'ultimo argomento che è il nome della funzione.Array.prototype.slice.call(arguments, 0, arguments.length - 1)


0

Seguendo queste 2 guide a-way-let-users-define-custom-made-bound-if-istruzioni e aiutanti associati personalizzati sono stato in grado di adattare le mie viste condivise in questo post su stackoverflow per usare questo invece dello standard # if statement. Questo dovrebbe essere più sicuro del semplice lancio di un #if lì dentro.

Gli helper personalizzati associati in quel senso sono eccezionali.

<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>

Sto usando la brace progetto per creare la mia applicazione Ember.

Configurazione attuale al momento di questo post:

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: -------------------------------

0

In Ember.js puoi usare inline if helper in if block helper. Può sostituire ||l'operatore logico, ad esempio:

{{#if (if firstCondition firstCondition secondCondition)}}
  (firstCondition || (or) secondCondition) === true
{{/if}}

0

Puoi farlo semplicemente usando l'operatore logico come mostrato di seguito:

{{#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}}

Prima di chiudere se riesci a scrivere la tua logica aziendale


0

Puoi usare il seguente codice:

{{#if selection1}}
    doSomething1
{{else}}
   {{#if selection2}}
       doSomething2
   {{/if}}
{{/if}}

Spiega di più sui tuoi pensieri e sui tuoi processi, può essere molto difficile per le persone capire la tua soluzione se non conoscono il contesto o sono nuovi nella lingua.
sig.

-1

Ecco un approccio che sto usando per ember 1.10 e ember-cli 2.0.

// 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));
});

Quindi puoi usarlo nei tuoi modelli in questo modo:

// 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}}

Dove gli argomenti l'espressione vengono passati come p0, p1, p2ecc e p0possono anche essere indicate come this.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.