Opérateur logique dans un conditionnel guidbars.js {{#if}}

479

Existe-t-il un moyen dans le guidon JS d'incorporer des opérateurs logiques dans l'opérateur conditionnel standard guidbars.js? Quelque chose comme ça:

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

Je sais que je pourrais écrire mon propre assistant, mais je voudrais d'abord m'assurer que je ne réinvente pas la roue.

Mike Robinson
la source

Réponses:

519

Cela est possible en «trichant» avec une aide de bloc. Cela va probablement à l'encontre de l'idéologie des personnes qui ont développé le guidon.

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

Vous pouvez ensuite appeler l'assistant dans le modèle comme ceci

{{#ifCond v1 v2}}
    {{v1}} is equal to {{v2}}
{{else}}
    {{v1}} is not equal to {{v2}}
{{/ifCond}}
Nick Kitto
la source
54
Cela va à l'encontre de la nature sans logique du guidon / moustache, mais est certainement utile néanmoins, merci!
Bala Clark
6
Notez que cela ne fonctionne tout simplement pas avec les propriétés liées (lecture, liaisons Ember). Il convient aux valeurs littérales, mais ne résout pas les propriétés du modèle (testé avec Ember 1.0.0-rc.8 et Handlebars 1.0.0), et registerBoundHelperne peut pas gérer la syntaxe des guidons. La solution consiste à créer une vue personnalisée: stackoverflow.com/questions/18005111/…
Warren Seine
28
@BalaClark est-il vraiment sans logique? Je veux dire qu'il a toujours des déclarations «si» - ce n'est pas parce qu'elles sont intentionnellement paralysées que cela change la philosophie.
phreakhead
111
Je n'ai jamais compris pourquoi les développeurs aiment se handicaper.
StackOverflowed
36
Je ne comprends pas pourquoi ET / OU ne peut pas faire partie des guidons. Cela ne va pas à l'encontre de la nature sans logique, car il y a déjà IF, UNLESS et EACH ... tant pis pour logicless
Asaf
445

Aller plus loin dans la solution. Cela ajoute l'opérateur de comparaison.

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

Utilisez-le dans un modèle comme celui-ci:

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

Version 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
Jim
la source
20
n'oubliez pas '||'et '&&'. J'ai ajouté ces cas et ils sont très utiles.
Jason
20
Être un noob au guidon, une chose qui n'était pas claire, c'est que vous devez passer l'opérateur sous forme de chaîne, sinon le compilateur affichera une erreur lors de la création de jetons de votre modèle. {{#ifCond true '==' false}}
Joe Holloway
2
J'ai trouvé que les valeurs n'étaient pas évaluées pour les attributs d'objet. Ajout des aides suivantes v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
ZX12R
4
mais si v1 et v2 ont également une condition, comment puis-je l'utiliser? par exemple: if (value == "a" || value == "b")
Krishna
3
Pouvez-vous faire autre chose avec ça?
jbyrd
160

Le guidon prend en charge les opérations imbriquées. Cela offre beaucoup de flexibilité (et un code plus propre) si nous écrivons notre logique un peu différemment.

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

En fait, nous pouvons ajouter toutes sortes de logiques:

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

Enregistrez simplement ces aides:

Handlebars.registerHelper({
    eq: (v1, v2) => v1 === v2,
    ne: (v1, v2) => v1 !== v2,
    lt: (v1, v2) => v1 < v2,
    gt: (v1, v2) => v1 > v2,
    lte: (v1, v2) => v1 <= v2,
    gte: (v1, v2) => v1 >= v2,
    and() {
        return Array.prototype.every.call(arguments, Boolean);
    },
    or() {
        return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
    }
});
kevlened
la source
5
Notez que cela n'était pas possible avant HTMLBars dans Ember 1.10. En outre, ces assistants viennent en tant qu'addon Ember CLI si vous préférez: github.com/jmurphyau/ember-truth-helpers .
stephen.hanson
1
De cette façon, sans optionsexécution, il est préférable de conserver la ifméthode et plus facile à tester. Merci!
Washington Botelho,
25
Nous semblons avoir intégré Lisp dans les guidons.
jdunning
8
Vos assistants andet vous orne travaillez qu'avec 2 paramètres, ce qui n'est pas ce que vous voulez. J'ai réussi à retravailler les assistants andet orpour prendre en charge plus de deux paramètres. Utilisez ce one-liner pour and: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);et utiliser une doublure pour or: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);.
Luke
3
Une version un peu plus avancée qui peut prendre plusieurs paramètres sur chaque opérateur.
Nate
87

prendre celui-ci un cran, pour ceux d'entre vous qui vivent sur le bord.

gist : https://gist.github.com/akhoury/9118682 Démo : extrait de code ci-dessous

Aide au guidon: {{#xif EXPRESSION}} {{else}} {{/xif}}

un assistant pour exécuter une instruction IF avec n'importe quelle expression

  1. EXPRESSION est une chaîne correctement échappée
  2. Oui, vous DEVEZ échapper correctement les littéraux de chaîne ou simplement alterner les guillemets simples et doubles
  3. vous pouvez accéder à n'importe quelle fonction ou propriété globale, c.-à-d. encodeURIComponent(property)
  4. cet exemple suppose que vous avez transmis ce contexte à votre guidon template( {name: 'Sam', age: '20' } ), l'avis ageest un string, juste pour que je puisse faire une démonstration parseInt()plus tard dans ce post

Usage:

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

Production

<p>
  BOOM
</p>

JavaScript: (cela dépend d'un autre assistant - continuez à lire)

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

Aide au guidon: {{x EXPRESSION}}

Un assistant pour exécuter des expressions javascript

  1. EXPRESSION est une chaîne correctement échappée
  2. Oui, vous DEVEZ échapper correctement les littéraux de chaîne ou simplement alterner les guillemets simples et doubles
  3. vous pouvez accéder à n'importe quelle fonction ou propriété globale, c.-à-d. parseInt(property)
  4. cet exemple suppose que vous avez transmis ce contexte à votre guidon template( {name: 'Sam', age: '20' } ), ageest stringà des fins de démonstration, il peut être n'importe quoi.

Usage:

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

Production:

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

JavaScript:

Cela semble un peu grand car j'ai développé la syntaxe et commenté presque chaque ligne à des fins de clarté

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

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

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

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

var data = [{
  firstName: 'Joan',
  age: '21',
  email: '[email protected]'
}, {
  firstName: 'Sam',
  age: '18',
  email: '[email protected]'
}, {
  firstName: 'Perter',
  lastName: 'Smith',
  age: '25',
  email: '[email protected]'
}];

var source = $("#template").html();
var template = Handlebars.compile(source);
$("#main").html(template(data));
h1 {
  font-size: large;
}
.content {
  padding: 10px;
}
.person {
  padding: 5px;
  margin: 5px;
  border: 1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0/handlebars.min.js"></script>

<script id="template" type="text/x-handlebars-template">
  <div class="content">
    {{#each this}}
    <div class="person">
      <h1>{{x  "'Hi ' + firstName"}}, {{x 'lastName'}}</h1>
      <div>{{x '"you were born in " + ((new Date()).getFullYear() - parseInt(this.age, 10)) '}}</div>
      {{#xif 'parseInt(age) >= 21'}} login here:
      <a href="http://foo.bar?email={{x 'encodeURIComponent(email)'}}">
        	http://foo.bar?email={{x 'encodeURIComponent(email)'}}
        </a>
      {{else}} Please go back when you grow up. {{/xif}}
    </div>
    {{/each}}
  </div>
</script>

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

Moar

si vous voulez accéder à la portée de niveau supérieur, celle-ci est légèrement différente, l'expression est le JOIN de tous les arguments, utilisation: disons que les données de contexte ressemblent à ceci:

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

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

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

Javascript:

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

Handlebars.registerHelper("zif", function () {
    var options = arguments[arguments.length - 1]
    delete arguments[arguments.length - 1];
    return Handlebars.helpers["x"].apply(this, [Array.prototype.slice.call(arguments, 0).join(''), options]) ? options.fn(this) : options.inverse(this);
});
bentael
la source
15
C'est bien. Le guidon ne peut pas vous dire quoi faire :)
lemiant
1
:) merci, j'ai mis à jour l' essentiel pour ajouter quelques autres goodies (pas directement liés à cette question SO - mais dans l'esprit de faire ce que vous voulez à l'intérieur d'un modèle de guidon) Cependant, vous devez faire attention aux limitations, je n'ai pas 'ai pas trouvé un moyen d'accéder aux "niveaux de portée supérieurs" à partir de l'expression, disons que vous êtes dans chaque portée, {{#each}} ... {{xif ' ../name === this.name' }} {{/each}}... mais
j'étudie
1
trouvé une solution pour "l'accès à l'étendue supérieure" mais en utilisant un nouvel assistant, voir la réponse mise à jour, {{z ...}}helper
bentael
BOOM! Génial, maintenant je peux faire des conditions réelles dans mes remerciements partiels !
AncAinu
1
@rickysullivan essayez de remplacer le vôtre eval(expression);par ceci: eval('(function(){try{return ' + expression + ';}catch(e){}})();');- Je sais que cela devient moche, mais je ne peux pas penser à un moyen sûr de le faire - veuillez noter que ce n'est pas très "rapide" à exécuter, je ne le ferais pas dans énorme itération.
bentael
33

Il existe un moyen simple de le faire sans écrire une fonction d'aide ... Cela peut être fait complètement dans le modèle.

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

Modifier: Inversement, vous pouvez faire ou faire en faisant ceci:

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

Edit / Note: Sur le site Web du guidon: handlebarsjs.com voici les valeurs de falsification:

Vous pouvez utiliser l'aide if pour effectuer un rendu conditionnel d'un bloc. Si son argument renvoie false, undefined, null, "" ou [] (une valeur "falsy"), alors tout 'cond' (comme cond1 ou cond2) ne sera pas compté comme vrai.

Jono
la source
9
Pas vraiment, vous ne comparez pas deux valeurs, vous vous assurez simplement que les deux existent, c'est différent.
Cyril N.
3
En fait, il l'évalue de la même manière que javascript, à partir du site Web: "Vous pouvez utiliser l'aide if pour rendre conditionnellement un bloc. Si son argument renvoie false, undefined, null" "ou [] (une valeur" falsy "), Le guidon ne rendra pas le bloc. "
Jono
1
Vous avez raison, j'ai d'abord pensé que le test consistait à comparer deux valeurs, et non à tester les deux existaient. Mon mauvais, désolé.
Cyril N.
4
Cela ne fonctionne pas correctement. Si cond1 est vrai et con2 est faux, rien ne sera imprimé.
Tessa Lau
1
Hé @TessaLau, je pense que je vois d'où tu viens. Cependant, si vous dessinez un flux de contrôle, vous verrez que dans la toute première ligne déplace le flux de contrôle vers cette condition.
Jono
19

Un problème avec toutes les réponses publiées ici est qu'elles ne fonctionnent pas avec les propriétés liées, c'est-à-dire que la condition if n'est pas réévaluée lorsque les propriétés impliquées changent. Voici une version légèrement plus avancée de l'aide qui prend en charge les liaisons. Il utilise la fonction de liaison de la source Ember, qui est également utilisée pour implémenter l' #ifaide Ember normale .

Celui-ci est limité à une propriété liée unique sur le côté gauche, par rapport à une constante sur le côté droit, qui je pense est assez bon pour la plupart des fins pratiques. Si vous avez besoin de quelque chose de plus avancé qu'une simple comparaison, alors il serait peut-être bon de commencer à déclarer certaines propriétés calculées et d'utiliser à la #ifplace l'aide 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;
  });
});

Vous pouvez l'utiliser comme ceci:

{{#ifeq obj.some.property "something"}}
  They are equal!
{{/ifeq}}
devongovett
la source
C'est la réponse appropriée si vous utilisez Ember. Les autres solutions que vous avez mentionnées passeront simplement la clé au lieu de la valeur. BTW merci pour cela, a passé quelques heures à me tordre la tête.
J Lee
2
Quelqu'un at-il obtenu ce travail avec HTMLBars / Ember 1.10? Ember.Handlebars.bind ne semble plus exister.
Linda
J'ai utilisé à l'origine registerBoundHelper à l'origine, mais quand il a changé de condition, il ne changerait pas la valeur else et vice versa. Cette méthode fonctionne avec ember pour changer :) Cela devrait avoir beaucoup plus de votes
Matt Vukomanovic
13

Solution améliorée qui fonctionne essentiellement avec n'importe quel opérateur binaire (au moins les nombres, les chaînes ne fonctionnent pas bien avec eval, PRENEZ SOIN DE L'INJECTION POSSIBLE DU SCRIPT SI VOUS UTILISEZ UN OPÉRATEUR NON DÉFINI AVEC DES ENTRÉES UTILISATEUR):

Handlebars.registerHelper("ifCond",function(v1,operator,v2,options) {
    switch (operator)
    {
        case "==":
            return (v1==v2)?options.fn(this):options.inverse(this);

        case "!=":
            return (v1!=v2)?options.fn(this):options.inverse(this);

        case "===":
            return (v1===v2)?options.fn(this):options.inverse(this);

        case "!==":
            return (v1!==v2)?options.fn(this):options.inverse(this);

        case "&&":
            return (v1&&v2)?options.fn(this):options.inverse(this);

        case "||":
            return (v1||v2)?options.fn(this):options.inverse(this);

        case "<":
            return (v1<v2)?options.fn(this):options.inverse(this);

        case "<=":
            return (v1<=v2)?options.fn(this):options.inverse(this);

        case ">":
            return (v1>v2)?options.fn(this):options.inverse(this);

        case ">=":
         return (v1>=v2)?options.fn(this):options.inverse(this);

        default:
            return eval(""+v1+operator+v2)?options.fn(this):options.inverse(this);
    }
});
Vincent
la source
comment utiliseriez-vous cela dans un modèle? en particulier la partie options.fn?
qodeninja
{{ifCond val1 '||' val2}} true {{else}} false {{/ if}} il renvoie options.fn (true, la clause ifCond) s'il est correct, sinon il renvoie options.inverse (false, la clause else) s'il est incorrect.
Nick Kitto
1
En raison de la mise en garde mentionnée à propos de l'injection de script, je déconseille fortement d'utiliser cet assistant. Dans une grande base de code, cela pourrait facilement être responsable d'un problème de sécurité désagréable sur la ligne
Jordan Sitkin
8

Voici une solution si vous souhaitez vérifier plusieurs conditions:

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

Usage:

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

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

Voici un lien vers l'assistant de bloc que j'utilise: l' assistant de bloc de comparaison . Il prend en charge tous les opérateurs standard et vous permet d'écrire du code comme indiqué ci-dessous. C'est vraiment très pratique.

{{#compare Database.Tables.Count ">" 5}}
There are more than 5 tables
{{/compare}}
CleanTheRuck
la source
1
Ce devrait être le vote gagnant. Natif et destiné. Je trouve presque chaque fois que si vous écrivez un nouvel assistant, vous y pensez trop.
augurone
2
@augurone ce n'est pas un assistant natif. Si vous suivez le lien, vous verrez qu'il s'agit d'un assistant défini par l'utilisateur.
gfullam
@gfullam vous avez raison, j'utilisais le guidon dans l'assemblage, qui inclut nativement cet assistant. Ma faute.
augurone
4

Semblable à la réponse de Jim, mais en utilisant un peu de créativité, nous pourrions également faire quelque chose comme ceci:

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

Ensuite, pour l'utiliser, nous obtenons quelque chose comme:

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

Je suggérerais de déplacer l'objet hors de la fonction pour de meilleures performances, mais sinon vous pouvez ajouter n'importe quelle fonction de comparaison que vous souhaitez, y compris "et" et "ou".

ars265
la source
3

Une autre alternative consiste à utiliser le nom de la fonction dans #if. Le #ifdétectera si le paramètre est fonctionnel et s'il l'est, il l'appellera et utilisera son retour pour vérifier la véracité. Ci-dessous, myFunction obtient le contexte actuel comme this.

{{#if myFunction}}
  I'm Happy!
{{/if}}
Shital Shah
la source
Vous auriez donc besoin d'ajouter une fonction dans le contexte? L'exécution de code à partir d'un contexte est une faille de sécurité, car la source du code pourrait être inconnue. Cela peut être exploité pour une attaque XSS.
T Nguyen
Oui, vous devez ajouter une fonction dans le contexte. Dans un site Web mal conçu, oui, cela pourrait être une faille de sécurité. Mais dans ce cas, il y en aurait beaucoup d'autres.
Shital Shah
C'est la voie préférée .. TY.
elad.chen
3

Malheureusement, aucune de ces solutions ne résout le problème de l'opérateur "OU" "cond1 || cond2".

  1. Vérifiez si la première valeur est vraie
  2. Utilisez "^" (ou) et vérifiez si sinon cond2 est vrai

    {{#if cond1}} FAITES L'ACTION {{^}} {{#if cond2}} FAITES L'ACTION {{/ if}} {{/ if}}

Il enfreint la règle DRY. Alors pourquoi ne pas utiliser partiel pour le rendre moins salissant

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

Je peux comprendre pourquoi vous voudriez créer une aide pour les situations où vous avez un grand nombre de comparaisons variées à effectuer dans votre modèle, mais pour un nombre relativement petit de comparaisons (ou même une, ce qui m'a amené à cette page dans en premier lieu), il serait probablement plus facile de définir une nouvelle variable de guidon dans votre appel de fonction de rendu de vue, comme:

Passer au guidon lors du rendu:

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

puis dans votre modèle de guidon:

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

Je mentionne cela pour des raisons de simplicité, et aussi parce que c'est une réponse qui peut être rapide et utile tout en respectant la nature sans logique des guidons.

Programmeur Dan
la source
3

Installez le module complémentaire Ember Truth Helpers en exécutant la commande ci-dessous

ember installer ember-vérité-helpers

vous pouvez commencer à utiliser la plupart des opérateurs logiques (eq, not-eq, not et and, or, gt, gte, lt, lte, xor).

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

Vous pouvez même inclure une sous-expression pour aller plus loin,

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

Encore une autre solution tordue pour un assistant ternaire:

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

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

Ou un simple assistant de fusion:

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

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

Étant donné que ces caractères n'ont pas de signification particulière dans le balisage du guidon, vous êtes libre de les utiliser pour les noms d'assistance.

Moritz Friedrich
la source
1

J'ai trouvé un paquet npm fait avec CoffeeScript qui a beaucoup d'aides incroyablement utiles pour les guidons. Jetez un œil à la documentation dans l'URL suivante:

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

Vous pouvez faire un wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgz pour les télécharger et voir le contenu du package.

Vous serez capable de faire des choses comme {{#is number 5}}ou{{formatDate date "%m/%d/%Y"}}

Cristian Rojas
la source
1

si vous voulez simplement vérifier si l'un ou l'autre élément est présent, vous pouvez utiliser cet assistant personnalisé

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

comme ça

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

si vous devez également pouvoir avoir un "ou" pour comparer les valeurs de retour de fonction je préfère ajouter une autre propriété qui renvoie le résultat souhaité.

Les modèles devraient être sans logique après tout!

flamme profonde
la source
1

Je viens de venir à ce poste à partir d'une recherche Google sur la façon de vérifier si une chaîne est égale à une autre chaîne.

J'utilise HandlebarsJS dans NodeJS côté serveur, mais j'utilise également les mêmes fichiers de modèle sur le front-end en utilisant la version navigateur de HandlebarsJS pour l'analyser. Cela signifiait que si je voulais un assistant personnalisé, je devrais le définir à 2 endroits différents, ou affecter une fonction à l'objet en question - trop d'effort !!

Ce que les gens oublient, c'est que certains objets ont des fonctions héritées qui peuvent être utilisées dans le modèle de moustache. Dans le cas d'une chaîne:

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.

Nous pouvons utiliser cette méthode pour renvoyer soit un tableau de correspondances, soit nullsi aucune correspondance n'a été trouvée. C'est parfait, car en consultant la documentation 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.

Donc...

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

MISE À JOUR:

Après avoir testé sur tous les navigateurs, cela ne fonctionne pas sur Firefox . HandlebarsJS transmet d'autres arguments à un appel de fonction, ce qui signifie que lorsque String.prototype.match est appelé, le deuxième argument (c'est-à-dire les indicateurs Regexp pour l'appel de fonction de correspondance selon la documentation ci-dessus) semble être passé. Firefox voit cela comme une utilisation obsolète de String.prototype.match, et se brise donc.

Une solution consiste à déclarer un nouveau prototype fonctionnel pour l'objet String JS et à l'utiliser à la place:

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

Assurez-vous que ce code JS est inclus avant d'exécuter votre fonction Handlebars.compile (), puis dans votre modèle ...

{{#your_string}}
    {{#if (includes "what_youre_looking_for")}} 
        String found :)
    {{else}}
        No match found :(
    {{/if}}
{{/your_string}}
Jon
la source
Mis à jour pour Firefox, c'est ce que j'utilise actuellement
Jon
1

Ici, nous avons des guidons vanille pour de multiples && et || logiques (et 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

Vous ne savez pas si c'est "sûr" d'utiliser "et" et "ou" ... peut-être changer pour quelque chose comme "op_and" et "op_or"?

bob
la source
1

Solution correcte pour 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);
}); 

Appelez ensuite comme suit

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

BTW: Notez que la solution donnée ici est incorrecte, il ne soustrait pas le dernier argument qui est le nom de la fonction. https://stackoverflow.com/a/31632215/1005607

Son ET / OR original était basé sur la liste complète des arguments

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

Quelqu'un peut-il changer cette réponse? Je viens de perdre une heure à essayer de corriger quelque chose dans une réponse recommandée par 86 personnes. Le correctif consiste à filtrer le dernier argument qui est le nom de la fonction.Array.prototype.slice.call(arguments, 0, arguments.length - 1)

gène b.
la source
0

En suivant ces 2 guides sur la façon de laisser les utilisateurs définir des instructions if-bound-made- custom et des aides liées personnalisées, j'ai pu ajuster mes vues partagées dans ce post sur stackoverflow pour l'utiliser au lieu du standard # instruction if. Cela devrait être plus sûr que de simplement y jeter un #if.

Les assistants liés personnalisés dans cet esprit sont exceptionnels.

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

J'utilise le braise cli projet pour créer mon application ember.

Configuration actuelle au moment de cette publication:

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

Dans Ember.js, vous pouvez utiliser inline if helper dans if block helper. Il peut remplacer ||l'opérateur logique, par exemple:

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

Vous pouvez le faire simplement en utilisant l'opérateur logique comme celui ci-dessous:

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

Avant de fermer si vous pouvez écrire votre logique métier

Kunwar Babu
la source
0

Vous pouvez utiliser le code suivant:

{{#if selection1}}
    doSomething1
{{else}}
   {{#if selection2}}
       doSomething2
   {{/if}}
{{/if}}
varuni
la source
Veuillez expliquer plus en détail vos pensées et votre processus, il peut être très difficile pour les gens de comprendre votre solution s'ils ne connaissent pas le contexte ou sont nouveaux dans la langue.
mrhn
-1

Voici une approche que j'utilise pour ember 1.10 et 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));
});

Ensuite, vous pouvez l'utiliser dans vos modèles comme ceci:

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

Lorsque les arguments à l'expression sont passés en tant que p0, p1, p2etc. et p0peuvent également être référencés comme this.

Michael
la source