Operador lógico em um condicional handlebars.js {{#if}}


479

Existe uma maneira no JS de guidão incorporar operadores lógicos no operador condicional padrão handlebars.js? Algo assim:

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

Sei que poderia escrever meu próprio ajudante, mas primeiro gostaria de ter certeza de que não estou reinventando a roda.

Respostas:


519

Isso é possível 'trapaceando' com um auxiliar de bloco. Provavelmente isso vai contra a ideologia das pessoas que desenvolveram o guidão.

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

Você pode chamar o ajudante no modelo como este

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

54
Isso contraria a natureza lógica do guidão / bigode, mas certamente é útil, mesmo assim, obrigado!
Bala Clark

6
Observe que isso simplesmente não funciona com propriedades associadas (leia, Ligações Ember). É bom com valores literais, mas não resolve as propriedades do modelo (testado com o Ember 1.0.0-rc.8 e o Handlebars 1.0.0), e registerBoundHelpernão pode lidar com a sintaxe do Handlebars. A solução alternativa é criar uma exibição personalizada: stackoverflow.com/questions/18005111/…
Warren Seine

28
@BalaClark é realmente sem lógica? Quero dizer, ele ainda possui declarações "se" - apenas porque são intencionalmente aleijadas não muda a filosofia.
Phreakhead #

111
Eu nunca entendi por que os desenvolvedores gostam de se prejudicar.
StackOverflowed

36
Não entendo por que AND / OR não pode fazer parte do guidão. Ele não vai contra a natureza logicless desde já há IF, a menos que, e EACH ... tanto por logicless
Asaf

445

Levando a solução um passo adiante. Isso adiciona o operador de comparação.

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

Use-o em um modelo como este:

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

Versão 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
não esqueça '||'e '&&'. Eu adicionei esses casos e eles são muito úteis.
21413 Jason As

20
Sendo um noob no guidão, uma coisa que não ficou clara é que você precisa passar o operador como uma string ou o compilador irá errar ao tokenizar seu modelo. {{#ifCond true '==' false}}
Joe Holloway

2
Eu achei que os valores não eram avaliados para atributos de objeto. Adicionando as seguintes ajudas v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ZX12R 3/15/15

4
mas se v1 e v2 também uma condição, como posso usar? por ex: if (valor == "a" || valor == "b")
Krishna

3
Você pode fazer outra coisa se com isso?
Jbyrd

160

O guidão suporta operações aninhadas. Isso fornece muita flexibilidade (e código mais limpo) se escrevermos nossa lógica de maneira um pouco diferente.

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

De fato, podemos adicionar todos os tipos de lógica:

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

Basta registrar estes ajudantes:

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
Observe que isso não era possível até o HTMLBars no Ember 1.10. Além disso, esses auxiliares vêm como um complemento da CLI do Ember, se você preferir: github.com/jmurphyau/ember-truth-helpers .
31515 stephen.hanson

1
Dessa forma, sem optionsexecução, é melhor manter o ifmétodo e mais fácil de testar. Obrigado!
Washington Botelho

25
Parece que construímos o Lisp no guidão.
Jdunning # 15/16

8
Você ande seus orajudantes trabalham apenas com 2 parâmetros, que não é o que você deseja. Eu consegui refazer ambas as ande orajudantes para suportar mais de dois parâmetros. Utilize este one-liner para and: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);e usar este one-liner para or: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);.
Lucas

3
Uma versão um pouco mais avançada que pode assumir vários parâmetros em cada operador.
Nate

87

levando este a um nível, para aqueles que vivem no limite.

gist : https://gist.github.com/akhoury/9118682 Demo : snippet de código abaixo

Auxiliar do guidão: {{#xif EXPRESSION}} {{else}} {{/xif}}

um auxiliar para executar uma instrução IF com qualquer expressão

  1. EXPRESSION é uma String com escape apropriado
  2. Sim, você PRECISA escapar corretamente dos literais de string ou apenas alternar aspas simples e duplas
  3. você pode acessar qualquer função ou propriedade global, ou seja, encodeURIComponent(property)
  4. Neste exemplo, assume que você passou esse contexto para o guidão template( {name: 'Sam', age: '20' } ), o aviso ageé um string, apenas para que eu possa demonstrar parseInt()mais adiante neste post

Uso:

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

Resultado

<p>
  BOOM
</p>

JavaScript: (depende de outro ajudante - continue lendo)

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

Auxiliar do guidão: {{x EXPRESSION}}

Um auxiliar para executar expressões javascript

  1. EXPRESSION é uma String com escape apropriado
  2. Sim, você PRECISA escapar corretamente dos literais de string ou apenas alternar aspas simples e duplas
  3. você pode acessar qualquer função ou propriedade global, ou seja, parseInt(property)
  4. este exemplo assume que você passou esse contexto para o guidão template( {name: 'Sam', age: '20' } ), ageé stringpara fins de demonstração, pode ser qualquer coisa.

Uso:

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

Resultado:

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

JavaScript:

Parece um pouco grande, porque ampliei a sintaxe e comentei quase todas as linhas para fins de clareza

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 você deseja acessar o escopo de nível superior, este é um pouco diferente, a expressão é JOIN de todos os argumentos, use: say dados de contexto se parecem com isso:

// 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
Isso é ótimo. Guidão não posso te dizer o que fazer :)
lemiant

1
:) obrigado, atualizei um pouco a essência para adicionar mais algumas guloseimas (não diretamente relacionadas a essa pergunta do SO - mas no espírito de fazer o que você quer dentro de um modelo de guidão) No entanto, você deve observar as limitações, mas não 't encontrado uma maneira de acesso 'níveis de escopo superiores' de dentro da expressão, digamos que você está em um cada escopo, {{#each}} ... {{xif ' ../name === this.name' }} {{/each}}... mas eu ainda estou investigando ..
bentael

1
resposta encontrada uma solução para o "acesso âmbito superior", mas usando um novo ajudante, ver atualizado, {{z ...}}ajudante
bentael

ESTRONDO ! Impressionante, agora posso fazer uma condição real dentro dos meus agradecimentos parciais !
precisa saber é o seguinte

1
@ Rickysullivan tente substituir o seu eval(expression);por este: eval('(function(){try{return ' + expression + ';}catch(e){}})();');- eu sei que isso está ficando feio, mas não consigo pensar em uma maneira segura de fazer isso - esteja ciente de que isso não é muito "rápido" para executar, eu não faria isso em iteração enorme.
bentael

33

Existe uma maneira simples de fazer isso sem escrever uma função auxiliar ... Isso pode ser feito completamente no modelo.

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

Edit: Por outro lado, você pode fazer ou fazer isso:

{{#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: No site do guiador: handlebarsjs.com, aqui estão os valores de falsidade:

Você pode usar o auxiliar if para renderizar um bloco condicionalmente. Se seu argumento retornar falso, indefinido, nulo "" ou [] (um valor "falso"), qualquer 'cond' (como cond1 ou cond2) não será contado como verdadeiro.


9
Na verdade, você não compara dois valores, apenas garante que ambos exista, é diferente.
Cyril N.

3
Na verdade, ele é avaliado da mesma forma que o javascript, no site: "Você pode usar o auxiliar if para renderizar um bloco condicionalmente. Se o argumento retornar falso, indefinido, nulo" "" ou [] (um valor "falso"), O guidão não renderiza o bloco ".
Jono 04/04

1
Você está certo, primeiro pensei que o teste fosse comparar dois valores, e não o teste de ambos. Meu mal, desculpe.
Cyril N.

4
Isso não funciona corretamente. Se cond1 for verdadeiro e con2 for falso, nada será impresso.
Tessa Lau

1
Hey @TessaLau, acho que vejo de onde você vem. No entanto, se você desenhar um fluxo de controle, verá que, na primeira linha, move o fluxo de controle para essa condição.
Jono

19

Um problema com todas as respostas postadas aqui é que elas não funcionam com propriedades associadas, ou seja, a condição if não é reavaliada quando as propriedades envolvidas são alteradas. Aqui está uma versão um pouco mais avançada das ligações de suporte do auxiliar. Ele usa a função de ligação da fonte Ember, que também é usada para implementar o #ifauxiliar Ember normal .

Essa é limitada a uma única propriedade vinculada no lado esquerdo, comparada a uma constante no lado direito, o que eu acho que é bom o suficiente para a maioria dos propósitos práticos. Se você precisar de algo mais avançado do que uma simples comparação, talvez seja bom começar a declarar algumas propriedades calculadas e usar o #ifauxiliar normal .

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

Você pode usá-lo assim:

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

Esta é a resposta apropriada se você estiver usando o Ember. As outras soluções, como você mencionou, passarão a chave em vez do valor. Entre, obrigado por isso, passei algumas horas torcendo minha cabeça.
J Lee

2
Alguém conseguiu isso trabalhando com o HTMLBars / Ember 1.10? O Ember.Handlebars.bind não parece mais existir.
Linda

Eu originalmente usado registerBoundHelper originalmente, mas depois, quando se mudou condição de que não iria mudar para o valor mais e volta .. Este método funciona com brasa para mudar :) Deve ter muito mais vota-se
Matt Vukomanovic

13

Solução aprimorada que basicamente funciona com qualquer operador binário (pelo menos números, seqüências de caracteres não funcionam bem com eval, CUIDADO COM A INJEÇÃO DE SCRIPT POSSÍVEL SE USAR UM OPERADOR NÃO DEFINIDO COM ENTRADAS DE USUÁRIO):

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

como você usaria isso em um modelo? especialmente a parte options.fn?
Qodeninja

{{ifCond val1 '||' val2}} true {{else}} false {{/ if}} retorna options.fn (true, a cláusula ifCond) se estiver correta, caso contrário, retorna options.inverse (false, a cláusula else) se estiver incorreta.
precisa

1
Devido à advertência mencionada sobre a injeção de script, eu recomendaria fortemente não usar esse auxiliar. Em uma grande base de código este poderia facilmente ser responsável por um problema de segurança desagradável para baixo da linha
Jordan Sitkin

8

Aqui está uma solução se você quiser verificar várias condições:

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

Aqui está um link para o auxiliar de bloco que eu uso: auxiliar de bloco de comparação . Ele suporta todos os operadores padrão e permite escrever o código como mostrado abaixo. É realmente bastante útil.

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

1
Este deve ser o voto vencedor. Nativo e pretendido. Acho quase sempre que, se você está escrevendo um novo ajudante, está pensando demais.
285 Augurone

2
@augurone este não é um ajudante nativo. Se você seguir o link, verá que ele é um auxiliar definido personalizado.
gfullam

@gfullam você está certo, eu estava usando guidão em assemble, o que inclui esse auxiliar nativamente. Foi mal.
28515 Augurone

4

Semelhante à resposta de Jim, mas usando um pouco de criatividade, também podemos fazer algo assim:

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

Então, para usá-lo, temos algo como:

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

Eu sugeriria mover o objeto para fora da função para obter melhor desempenho, mas, caso contrário, você poderá adicionar qualquer função de comparação desejada, incluindo "e" e "ou".


3

Uma outra alternativa é usar o nome da função em #if. Ele #ifdetectará se o parâmetro é função e, se for, ele o chamará e usará seu retorno para verificação da verdade. Abaixo myFunction obtém o contexto atual como this.

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

Então você precisaria adicionar uma função ao contexto? A execução de código de um contexto é uma falha de segurança, pois a origem do código pode ser desconhecida. Isso pode ser explorado para um ataque XSS.
T # Nguyen

Sim, você precisa adicionar uma função ao contexto. Em um site mal projetado, sim, isso pode ser uma falha de segurança. Mas, nesse caso, haveria muitos outros.
Shital Shah

Esta é a maneira preferida .. TY.
elad.chen

3

Infelizmente, nenhuma dessas soluções resolve o problema do operador "OR" "cond1 || cond2".

  1. Verifique se o primeiro valor é verdadeiro
  2. Use "^" (ou) e verifique se, caso contrário, cond2 é verdadeiro

    {{#if cond1}} FAÇA A AÇÃO {{^}} {{#if cond2}} FAÇA A AÇÃO {{/ if}} {{/ if}}

Quebra a regra SECA. Então, por que não usar parcial para torná-lo menos confuso

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

3

Entendo por que você desejaria criar um auxiliar para situações em que você tem um grande número de comparações variadas para executar em seu modelo, mas para um número relativamente pequeno de comparações (ou mesmo uma, que foi o que me levou a esta página em em primeiro lugar), provavelmente seria mais fácil definir uma nova variável de guidão em sua chamada de função de renderização de exibição, como:

Passe para o guidão no render:

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

e depois dentro do seu modelo de guidão:

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

Menciono isso por uma questão de simplicidade, e também porque é uma resposta que pode ser rápida e útil enquanto ainda cumpre a natureza lógica do guidão.


3

Instale o complemento Ember Truth Helpers executando o comando abaixo

brasa instalar brasa-verdade-ajudantes

você pode começar a usar a maioria dos operadores lógicos (eq, not-eq, not e e, ou, gt, gte, lt, lte, xor).

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

Você pode até incluir subexpressão para ir além,

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

2

Outra solução distorcida para um ajudante ternário:

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

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

Ou um simples auxiliar de coalescência:

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

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

Como esses caracteres não têm um significado especial na marcação do guidão, você pode usá-los como nomes auxiliares.


1

Eu encontrei um pacote npm feito com o CoffeeScript que tem muitos auxiliares incríveis e úteis para o guidão. Veja a documentação no seguinte URL:

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

Você pode fazer o wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgzdownload deles e ver o conteúdo do pacote.

Você será capaz de fazer coisas como {{#is number 5}}ou{{formatDate date "%m/%d/%Y"}}


1

se você quiser apenas verificar se um ou outro elemento está presente, use este auxiliar 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);
  }
});

como isso

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

se você também precisar ter um "ou" para comparar os valores de retorno da função , prefiro adicionar outra propriedade que retorne o resultado desejado.

Afinal, os modelos não devem ter lógica!



1

Acabei de chegar a este post de uma pesquisa no google sobre como verificar se uma string é igual a outra string.

Uso o HandlebarsJS no NodeJS, mas também os mesmos arquivos de modelo no front-end, usando a versão do navegador do HandlebarsJS para analisá-lo. Isso significava que, se eu quisesse um auxiliar personalizado, teria que defini-lo em 2 lugares separados ou atribuir uma função ao objeto em questão - muito esforço !!

O que as pessoas esquecem é que certos objetos têm funções herdadas que podem ser usadas no modelo de bigode. No caso de uma string:

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 esse método para retornar uma matriz de correspondências ou nullse nenhuma correspondência for encontrada. Isso é perfeito, porque olhar para a documentação do 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.

Assim...

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

ATUALIZAR:

Após o teste em todos os navegadores, isso não funciona no Firefox . O HandlebarsJS passa outros argumentos para uma chamada de função, o que significa que, quando String.prototype.match é chamado, o segundo argumento (ou seja, os sinalizadores Regexp para a chamada de função de correspondência conforme a documentação acima) parece estar sendo passado. O Firefox vê isso como um uso obsoleto de String.prototype.match, e assim quebra.

Uma solução alternativa é declarar um novo protótipo funcional para o objeto String JS e usá-lo:

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

Verifique se esse código JS está incluído antes de executar sua função Handlebars.compile () e, em seguida, no seu modelo ...

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

Atualizado para o Firefox, é isso que eu estou usando atualmente
Jon

1

Aqui temos guidão de baunilha para vários lógicos && e || (e ou):

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

Não tem tanta certeza se é "seguro" usar "e" e "ou" ... talvez mude para algo como "op_and" e "op_or"?


1

Solução correta 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);
}); 

Em seguida, ligue da seguinte maneira

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

BTW: Observe que a solução fornecida aqui está incorreta, ele não está subtraindo o último argumento, que é o nome da função. https://stackoverflow.com/a/31632215/1005607

Seu original AND / OR foi baseado na lista completa de argumentos

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

Alguém pode mudar essa resposta? Acabei de perder uma hora tentando consertar algo em uma resposta recomendada por 86 pessoas. A correção é filtrar o último argumento, que é o nome da função.Array.prototype.slice.call(arguments, 0, arguments.length - 1)


0

Seguindo esses dois guias, instruções de como definir como customizar o limite de if e os auxiliares de limite personalizados, consegui ajustar minhas visualizações compartilhadas nesta postagem no stackoverflow para usá-lo em vez do padrão # declaração if. Isso deve ser mais seguro do que apenas jogar um #if lá.

Os auxiliares vinculados personalizados nessa essência são excelentes.

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

Estou usando o projeto ember cli para criar meu aplicativo ember.

Configuração atual no momento desta postagem:

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

No Ember.js, você pode usar o auxiliar de linha, se o auxiliar de bloco. Pode substituir ||o operador lógico, por exemplo:

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

0

Você pode fazer isso simplesmente usando o operador lógico como este mostrado abaixo:

{{#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 fechar, se você pode escrever sua lógica de negócios


0

Você pode usar o seguinte código:

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

Por favor, explique mais sobre seus pensamentos e processos; pode ser muito difícil para as pessoas entenderem sua solução se elas não conhecerem o contexto ou forem novas no idioma.
mrhn 31/03

-1

Aqui está uma abordagem que estou usando para o ember 1.10 e o 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));
});

Então você pode usá-lo em seus modelos como este:

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

Onde os argumentos para a expressão são passados como p0, p1, p2etc e p0também pode ser referenciado como this.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.