Operador lógico en un manillars.js {{#if}} condicional


479

¿Hay alguna manera en el manillar JS para incorporar operadores lógicos en el operador condicional estándar handlebars.js? Algo como esto:

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

Sé que podría escribir mi propio ayudante, pero primero me gustaría asegurarme de no reinventar la rueda.

Respuestas:


519

Esto es posible 'haciendo trampa' con un ayudante de bloque. Esto probablemente va en contra de la ideología de las personas que desarrollaron manillares.

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

Luego puede llamar al ayudante en la plantilla de esta manera

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

54
Esto va en contra de la naturaleza sin lógica de Handlebars / Moustache, pero de todos modos es útil, ¡gracias!
Bala Clark

66
Tenga en cuenta que esto simplemente no funciona con propiedades enlazadas (lectura, enlaces Ember). Está bien con valores literales, pero no resuelve las propiedades del modelo (probado con Ember 1.0.0-rc.8 y Handlebars 1.0.0), y registerBoundHelperno puede manejar la sintaxis de Handlebars. La solución alternativa es crear una vista personalizada: stackoverflow.com/questions/18005111/…
Warren Seine

28
@BalaClark, ¿es realmente sin lógica? Quiero decir que todavía tiene declaraciones "si", solo porque están paralizadas intencionalmente no cambia la filosofía.
phreakhead

111
Nunca entendí por qué a los desarrolladores les gusta perjudicarse a sí mismos.
StackOverflowed

36
No entiendo por qué AND / OR no puede ser parte de Handlebars. No va en contra de la naturaleza sin lógica ya que ya hay SI, A MENOS, Y CADA ... tanto para sin lógica
Asaf

445

Llevando la solución un paso más allá. Esto agrega el operador de comparación.

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

Úselo en una plantilla como esta:

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

Versión de Script de café

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
no te olvides de '||'y '&&'. Agregué estos casos y son muy útiles.
Jason

20
Al ser un novato en el manillar, una cosa que no estaba clara es que debe pasar el operador como una cadena o, de lo contrario, el compilador se equivocará al tokenizar su plantilla. {{#ifCond true '==' false}}
Joe Holloway

2
Encontré que los valores no se evalúan para los atributos del objeto. Agregar las siguientes ayudas v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ZX12R

44
pero si v1 y v2 también son una condición, ¿cómo puedo usar? por ejemplo: if (value == "a" || value == "b")
Krishna

3
¿Puedes hacer otra cosa si con esto?
jbyrd

160

Los manillares admiten operaciones anidadas. Esto proporciona mucha flexibilidad (y un código más limpio) si escribimos nuestra lógica un poco diferente.

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

De hecho, podemos agregar todo tipo de lógica:

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

Simplemente registre estos ayudantes:

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

55
Tenga en cuenta que esto no fue posible hasta HTMLBars en Ember 1.10. Además, esos ayudantes vienen como un complemento Ember CLI si prefieres: github.com/jmurphyau/ember-truth-helpers .
stephen.hanson

1
De esta manera, sin optionsejecución es mejor mantener con ifmétodo y más fácil de probar. ¡Gracias!
Washington Botelho

25
Parece que hemos incorporado Lisp en manillares.
jdunning

8
Tu andy orayudantes solo trabajan con 2 parámetros, que no es lo que quieres. Me las arreglé para reelaborar tanto el andy los orayudantes para admitir más de dos parámetros. Utilice esta de una sola línea para and: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);Utilizando este de una sola línea para or: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);.
Lucas

3
Una versión un poco más avanzada que puede tomar múltiples parámetros en cada operador.
Nate

87

llevando esto a un nivel superior, para aquellos de ustedes que viven al límite.

gist : https://gist.github.com/akhoury/9118682 Demostración : fragmento de código a continuación

Ayudante de manillar: {{#xif EXPRESSION}} {{else}} {{/xif}}

un ayudante para ejecutar una instrucción IF con cualquier expresión

  1. EXPRESSION es una cadena escapada correctamente
  2. Sí, NECESITA escapar correctamente de los literales de cadena o simplemente alternar comillas simples y dobles
  3. puede acceder a cualquier función o propiedad global, es decir encodeURIComponent(property)
  4. este ejemplo asume que pasaste este contexto a tu manillar template( {name: 'Sam', age: '20' } ), el aviso agees a string, solo para que pueda hacer una demostración parseInt()más adelante en esta publicación

Uso:

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

Salida

<p>
  BOOM
</p>

JavaScript: (depende de otro ayudante, sigue leyendo)

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

Ayudante de manillar: {{x EXPRESSION}}

Un ayudante para ejecutar expresiones javascript

  1. EXPRESSION es una cadena escapada correctamente
  2. Sí, NECESITA escapar correctamente de los literales de cadena o simplemente alternar comillas simples y dobles
  3. puede acceder a cualquier función o propiedad global, es decir parseInt(property)
  4. este ejemplo asume que pasaste este contexto a tus manillares template( {name: 'Sam', age: '20' } ), agees un stringpropósito de demostración, puede ser cualquier cosa ...

Uso:

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

Salida:

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

JavaScript:

Esto parece un poco grande porque amplié la sintaxis y comenté sobre casi cada línea para mayor claridad

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>

Lamento

si desea acceder al alcance de nivel superior, este es ligeramente diferente, la expresión es la UNIÓN de todos los argumentos, uso: digamos que los datos de contexto se ven así:

// 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
Esto es genial. Los manillares no pueden decirte qué hacer :)
lemiant

1
:) gracias, actualicé la esencia un poco para agregar algunas cosas más (no directamente relacionadas con esta pregunta SO, pero con el espíritu de hacer lo que quieras dentro de una plantilla de manillar) Sin embargo, debes tener cuidado con las limitaciones, no tengo 't encontrar una manera de acceder a 'niveles superiores' de alcance dentro de la expresión, decir que estás en un ámbito cada uno, {{#each}} ... {{xif ' ../name === this.name' }} {{/each}}... pero todavía estoy investigando ..
bentael

1
encontró una solución para el "acceso de alcance superior" pero usando un nuevo ayudante, vea la respuesta actualizada, {{z ...}}ayudante
bentael

BOOM! ¡Impresionante, ahora puedo hacer una verdadera condición dentro de mi agradecimiento parcial !
AncAinu

1
@rickysullivan intente reemplazar su eval(expression);con esto: eval('(function(){try{return ' + expression + ';}catch(e){}})();');- Sé que esto se está poniendo feo, pero no puedo pensar en una forma segura de hacer esto - tenga en cuenta que esto no es muy "rápido" para ejecutar, no haría esto en Gran iteración.
bentael

33

Hay una manera simple de hacerlo sin escribir una función auxiliar ... Se puede hacer dentro de la plantilla por completo.

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

Editar: por el contrario, puede hacer o haciendo esto:

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

Editar / Nota: Desde el sitio web del manillar: handlebarsjs.com aquí están los valores falsos:

Puede usar el asistente if para representar condicionalmente un bloque. Si su argumento devuelve falso, indefinido, nulo, "" o [] (un valor "falso"), entonces cualquier 'cond' (como cond1 o cond2) no se contará como verdadero.


99
En realidad no, no se comparan dos valores, solo se asegura de que ambos existan, es diferente.
Cyril N.

3
En realidad, lo evalúa de la misma manera que lo hace javascript, desde el sitio web: "Puede usar el asistente if para representar condicionalmente un bloque. Si su argumento devuelve falso, indefinido, nulo" "o [] (un valor" falso "), Los manillares no representarán el bloque ".
Jono

1
Tienes razón, en primer lugar pensé que la prueba era comparar dos valores, no que existieran pruebas de ambos. Mi mal, lo siento.
Cyril N.

44
Esto no funciona correctamente. Si cond1 es verdadero y con2 es falso, no se imprimirá nada.
Tessa Lau

1
Hola @TessaLau, creo que veo de dónde vienes. Sin embargo, si extrae un flujo de control, verá que en la primera línea mueve el flujo de control a esa condición.
Jono

19

Un problema con todas las respuestas publicadas aquí es que no funcionan con propiedades enlazadas, es decir, la condición if no se vuelve a evaluar cuando cambian las propiedades involucradas. Aquí hay una versión un poco más avanzada de los enlaces de ayuda. Utiliza la función de enlace de la fuente Ember, que también se usa para implementar el #ifayudante Ember normal .

Esta se limita a una propiedad de enlace único en el lado izquierdo, en comparación con una constante en el lado derecho, que creo que es lo suficientemente bueno para la mayoría de los propósitos prácticos. Si necesita algo más avanzado que una simple comparación, entonces quizás sería bueno comenzar a declarar algunas propiedades calculadas y usar el #ifayudante normal en su lugar.

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

Puedes usarlo así:

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

Esta es la respuesta adecuada si está utilizando Ember. Las otras soluciones como mencionó simplemente pasarán la clave en lugar del valor. Por cierto, gracias por esto, pasé unas horas sacudiéndome la cabeza.
J Lee

2
¿Alguien ha conseguido que esto funcione con HTMLBars / Ember 1.10? Ember.Handlebars.bind ya no parece existir.
Linda

Originalmente usé registerBoundHelper originalmente, pero luego, cuando cambió la condición, no cambiaría al valor else y viceversa. Este método funciona con ascua para cambiar :) Debería tener muchos más votos arriba
Matt Vukomanovic

13

Solución mejorada que básicamente funciona con cualquier operador binario (al menos los números, las cadenas no funcionan bien con eval, TENGA CUIDADO DE LA POSIBLE INYECCIÓN DE ESCRITURA SI UTILIZA UN OPERADOR NO DEFINIDO CON ENTRADAS DE USUARIO):

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

¿Cómo usarías esto en una plantilla? especialmente la parte options.fn?
qodeninja

{{ifCond val1 '||' val2}} true {{else}} false {{/ if}} devuelve options.fn (verdadero, la cláusula ifCond) si es correcto; de lo contrario, devuelve options.inverse (falso, la cláusula else) si es incorrecto.
Nick Kitto

1
Debido a la advertencia mencionada sobre la inyección de script, recomendaría encarecidamente no usar este ayudante. En una base de código grande, esto podría ser fácilmente responsable de un desagradable problema de seguridad en el
futuro

8

Aquí hay una solución si desea verificar múltiples condiciones:

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

Aquí hay un enlace al ayudante de bloque que uso: ayudante de bloque de comparación . Es compatible con todos los operadores estándar y le permite escribir código como se muestra a continuación. Es realmente bastante útil.

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

1
Este debería ser el voto ganador. Nativo y destinado. Casi siempre encuentro que si estás escribiendo un nuevo ayudante lo estás pensando demasiado.
augurona

2
@augurone esto no es un ayudante nativo. Si sigue el enlace, verá que es un ayudante definido personalizado.
gfullam

@gfullam tienes razón, estaba usando el manillar en el ensamblaje, que incluye este ayudante de forma nativa. Culpa mía.
augurona

4

Similar a la respuesta de Jim, pero usando un poco de creatividad también podríamos hacer algo como esto:

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

Luego, para usarlo, obtenemos algo como:

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

Sugeriría mover el objeto fuera de la función para un mejor rendimiento, pero de lo contrario puede agregar cualquier función de comparación que desee, incluyendo "y" y "o".


3

Otra alternativa es usar el nombre de la función en #if. El #ifdetectará si el parámetro es función y si es entonces lo llamaremos y utilizar su cambio de cheque truthyness. Debajo de myFunction obtiene el contexto actual como this.

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

¿Entonces necesitarías agregar una función en el contexto? La ejecución de código desde un contexto es un agujero de seguridad, ya que la fuente del código podría ser desconocida. Esto puede ser explotado para un ataque XSS.
T Nguyen

Sí, debe agregar una función al contexto. En un sitio web mal diseñado, sí, esto podría ser un agujero de seguridad. Pero en ese caso, habría muchos otros.
Shital Shah

Esta es la forma preferida ... TY.
elad.chen

3

Lamentablemente, ninguna de estas soluciones resuelve el problema del operador "OR" "cond1 || cond2".

  1. Compruebe si el primer valor es verdadero
  2. Use "^" (o) y verifique si cond2 es verdadero

    {{#if cond1}} HAGA LA ACCIÓN {{^}} {{#if cond2}} HAGA LA ACCIÓN {{/ if}} {{/ if}}

Se rompe la regla SECO. Entonces, ¿por qué no usar parcial para hacerlo menos desordenado?

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

3

Puedo entender por qué querrías crear un asistente para situaciones en las que tienes que realizar una gran cantidad de comparaciones variadas dentro de tu plantilla, pero para una cantidad relativamente pequeña de comparaciones (o incluso una, que fue lo que me trajo a esta página en el primer lugar), probablemente sería más fácil definir una nueva variable de manillar en su llamada a la función de representación de vista, como:

Pase al manillar en el render:

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

y luego dentro de su plantilla de manillar:

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

Menciono esto por simplicidad, y también porque es una respuesta que puede ser rápida y útil mientras sigue cumpliendo con la naturaleza sin lógica de los Manillares.


3

Instale el complemento Ember Truth Helpers ejecutando el siguiente comando

ember instalar ember-truth-helpers

puede comenzar a usar la mayoría de los operadores lógicos (eq, not-eq, not, and, or, gt, gte, lt, lte, xor).

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

Incluso puedes incluir subexpresión para ir más allá,

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

2

Otra solución torcida para un ayudante ternario:

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

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

O un simple ayudante de fusión:

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

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

Dado que estos caracteres no tienen un significado especial en el marcado del manillar, puede usarlos para nombres de ayuda.


1

He encontrado un paquete npm hecho con CoffeeScript que tiene muchos ayudantes útiles increíbles para manillares. Eche un vistazo a la documentación en la siguiente URL:

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

Puede hacer una wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgzpara descargarlos y ver el contenido del paquete.

Podrás hacer cosas como {{#is number 5}}o{{formatDate date "%m/%d/%Y"}}


1

si solo desea verificar si uno u otro elemento está presente, puede usar este asistente personalizado

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

Me gusta esto

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

si también necesita poder tener un "o" para comparar los valores de retorno de la función , preferiría agregar otra propiedad que devuelva el resultado deseado.

¡Las plantillas deberían ser lógicas después de todo!



1

Acabo de llegar a esta publicación de una búsqueda en Google sobre cómo verificar si una cadena es igual a otra cadena.

Uso HandlebarsJS en NodeJS del lado del servidor, pero también uso los mismos archivos de plantilla en el front-end usando la versión del navegador de HandlebarsJS para analizarlo. Esto significaba que si quería un ayudante personalizado, tendría que definirlo en 2 lugares separados, o asignar una función al objeto en cuestión, ¡demasiado esfuerzo!

Lo que la gente olvida es que ciertos objetos tienen funciones heredadas que se pueden usar en la plantilla de bigote. En el caso de una cadena:

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.

Podemos usar este método para devolver una matriz de coincidencias o nullsi no se encontraron coincidencias. Esto es perfecto, porque mirando la documentación de 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.

Entonces...

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

ACTUALIZAR:

Después de probar en todos los navegadores, esto no funciona en Firefox . HandlebarsJS pasa otros argumentos a una llamada de función, lo que significa que cuando se llama a String.prototype.match, parece que se pasa el segundo argumento (es decir, los indicadores Regexp para la llamada a la función de coincidencia según la documentación anterior). Firefox ve esto como un uso obsoleto de String.prototype.match, por lo que se rompe.

Una solución alternativa es declarar un nuevo prototipo funcional para el objeto String JS y utilizarlo en su lugar:

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

Asegúrese de que este código JS esté incluido antes de ejecutar su función Handlebars.compile (), luego en su plantilla ...

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

Actualizado para Firefox, esto es lo que estoy usando actualmente
Jon

1

Aquí tenemos manillares de vainilla para múltiples lógicos && y || (y 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

¿No está tan seguro si es "seguro" usar "y" y "o" ... tal vez cambiar a algo como "op_and" y "op_or"?


1

Solución correcta para 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);
}); 

Luego llame de la siguiente manera

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

Por cierto: tenga en cuenta que la solución dada aquí es incorrecta, no está restando el último argumento que es el nombre de la función. https://stackoverflow.com/a/31632215/1005607

Su AND / OR original se basó en la lista completa de argumentos

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

¿Alguien puede cambiar esa respuesta? Acabo de perder una hora tratando de arreglar algo en una respuesta recomendada por 86 personas. La solución es filtrar el último argumento, que es el nombre de la función.Array.prototype.slice.call(arguments, 0, arguments.length - 1)


0

Siguiendo estas 2 guías para dejar que los usuarios definan declaraciones personalizadas con límites de ayuda y ayudantes con límites personalizados, pude ajustar mis vistas compartidas en esta publicación en stackoverflow para usar esto en lugar del estándar # si declaración. Esto debería ser más seguro que simplemente lanzar un #if allí.

Los ayudantes personalizados en esa esencia son excepcionales.

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

Estoy usando el ember cli proyecto para construir mi aplicación ember.

Configuración actual en el momento de esta publicación:

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

En Ember.js puedes usar inline if helper en if block helper. Puede reemplazar el ||operador lógico, por ejemplo:

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

0

Puede hacerlo simplemente usando el operador lógico como se muestra a continuación:

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

Antes de cerrar si puedes escribir tu lógica de negocios


0

Puedes usar el siguiente código:

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

Explique más acerca de sus pensamientos y procesos, puede ser muy difícil para las personas entender su solución si no conocen el contexto o son nuevos en el idioma.
Mr

-1

Aquí hay un enfoque que estoy usando para ember 1.10 y 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));
});

Luego puede usarlo en sus plantillas de esta manera:

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

Cuando se pasan los argumentos de la expresión en como p0, p1, p2etc., y p0también se puede hacer referencia como this.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.