Логический оператор в условном выражении handlebars.js {{#if}}


479

Есть ли способ в руле JS включить логические операторы в стандартный условный оператор handlebars.js? Что-то вроде этого:

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

Я знаю, что мог бы написать своего собственного помощника, но сначала я хотел бы убедиться, что я не изобретаю велосипед.

Ответы:


519

Это возможно путем «обмана» с помощью помощника блока. Это, вероятно, идет вразрез с идеологией людей, которые разработали руль.

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

Затем вы можете вызвать помощника в шаблоне, как это

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

54
Это идет вразрез с нелогичной природой Руль / Усов, но, тем не менее, полезно, спасибо!
Бала Кларк

6
Обратите внимание, что это просто не работает со связанными свойствами (читай, привязки Ember). Он подходит для литеральных значений, но не разрешает свойства модели (протестировано с Ember 1.0.0-rc.8 и Handlebars 1.0.0) и registerBoundHelperне может работать с синтаксисом Handlebars. Временное решение: создать собственное представление: stackoverflow.com/questions/18005111/…
Уоррен Сена,

28
@BalaClark это действительно логично, хотя? Я имею в виду, что у него все еще есть утверждения «если» - то, что они намеренно искалечены, не меняет философию.
phreakhead

111
Я никогда не понимал, почему разработчики любят ставить себя в тупик.
Переполнение

36
Я не понимаю, почему И / ИЛИ не может быть частью Руль. Это не идет вразрез с логикой, так как уже есть IF, UNLESS и EACH ... так много для логики
Асаф

445

Принимая решение на шаг дальше. Это добавляет оператор сравнения.

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

Используйте его в таком шаблоне:

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

Версия 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
не забывай про '||'и '&&'. Я добавил эти случаи, и они очень полезны.
Джейсон

20
Будучи новичком для руля, одна вещь, которая не была ясна, это то, что вы должны передать оператор в виде строки, иначе компилятор выдаст ошибку при токенизации вашего шаблона. {{#ififond true '==' false}}
Джо Холлоуэй

2
Я обнаружил, что значения не оцениваются для атрибутов объекта. Добавление следующих v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
подсказок

4
но если v1 и v2 также одно условие, то как я могу использовать? например: if (value == "a" || value == "b")
Кришна

3
Можете ли вы сделать еще, если с этим?
Jbyrd

160

Handlebars поддерживает вложенные операции. Это обеспечивает большую гибкость (и более чистый код), если мы пишем нашу логику немного по-другому.

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

На самом деле, мы можем добавить все виды логики:

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

Просто зарегистрируйте этих помощников:

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
Обратите внимание, что это было невозможно до HTMLBars в Ember 1.10. Кроме того, эти помощники могут стать дополнением Ember CLI, если хотите: github.com/jmurphyau/ember-truth-helpers .
stephen.hanson

1
Таким образом, без optionsвыполнения лучше придерживаться ifметода и легче тестировать. Спасибо!
Вашингтон Ботельо

25
Кажется, мы встроили Лисп в руль.
jdunning

8
Вы andи orпомощники работать только с 2 - мя параметрами, которые не то , что вы хотите. Мне удалось переделать andи orпомощников и помощников для поддержки более двух параметров. Используйте одну гильзу для and: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).every(Boolean);и использовать этот один вкладыш для or: return Array.prototype.slice.call(arguments, 0, arguments.length - 1).some(Boolean);.
Люк

3
Немного более продвинутая версия , которая может принимать несколько параметров по каждому оператору.
Ноябрь

87

взяв это на ступеньку выше, для тех из вас, кто живет на краю.

gist : https://gist.github.com/akhoury/9118682 Демонстрация : фрагмент кода ниже

Помощник руля: {{#xif EXPRESSION}} {{else}} {{/xif}}

помощник для выполнения оператора IF с любым выражением

  1. EXPRESSION - правильно экранированная строка
  2. Да, вам нужно правильно экранировать строковые литералы или просто чередовать одинарные и двойные кавычки
  3. Вы можете получить доступ к любой глобальной функции или свойству, т.е. encodeURIComponent(property)
  4. в этом примере предполагается, что вы передали этот контекст на руль template( {name: 'Sam', age: '20' } ), обратите внимание ageна это string, просто для того, чтобы я мог продемонстрировать parseInt()позже в этом посте

Применение:

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

Вывод

<p>
  BOOM
</p>

JavaScript: (это зависит от другого помощника - продолжайте читать)

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

Помощник руля: {{x EXPRESSION}}

Помощник для выполнения выражений JavaScript

  1. EXPRESSION - правильно экранированная строка
  2. Да, вам нужно правильно экранировать строковые литералы или просто чередовать одинарные и двойные кавычки
  3. Вы можете получить доступ к любой глобальной функции или свойству, т.е. parseInt(property)
  4. в этом примере предполагается, что вы передали этот контекст на руль template( {name: 'Sam', age: '20' } ), ageэто stringдля демонстрационной цели, это может быть что угодно ..

Применение:

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

Вывод:

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

JavaScript:

Это выглядит немного большим, потому что я расширил синтаксис и прокомментировал почти каждую строку для ясности

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

если вы хотите получить доступ к области верхнего уровня, это немного отличается, выражение является объединением всех аргументов, использование: скажем, данные контекста выглядят так:

// 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
Это замечательно. Руль не может сказать вам, что делать :)
lemiant

1
:) спасибо, я немного обновил суть, чтобы добавить еще несколько вкусностей (не связанных непосредственно с этим вопросом SO - но в духе выполнения того, что вы хотите внутри шаблона руля). Однако вы должны остерегаться ограничений, у меня нет не нашел способ получить доступ к "верхним уровням области видимости" из выражения, скажем, что ты находишься в каждой области видимости, {{#each}} ... {{xif ' ../name === this.name' }} {{/each}}... но я все еще расследую ..
bentael

1
нашел решение для "доступа в верхнюю область", но с использованием нового помощника, см. обновленный ответ, {{z ...}}помощник
bentael

БУМ! Круто, теперь я могу сделать реальное состояние внутри моей частичной благодарности!
AncAinu

1
@rickysullivan попробуйте заменить ваш eval(expression);на это: eval('(function(){try{return ' + expression + ';}catch(e){}})();');- я знаю, что это становится уродливым, но не могу придумать безопасный способ сделать это - пожалуйста, знайте, что это не очень "быстро" выполнить, я бы не стал делать это в огромная итерация.
бентаэль

33

Есть простой способ сделать это без написания вспомогательной функции ... Это можно сделать в шаблоне полностью.

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

Редактировать: И наоборот, вы можете сделать это, сделав это:

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

Редактировать / Примечание: с веб-сайта руля: handlebarsjs.com вот ложные значения:

Вы можете использовать помощник if для условного рендеринга блока. Если его аргумент возвращает false, undefined, null, "" или [] ("ложное" значение), то любой 'cond' (например, cond1 или cond2) не будет считаться истиной.


9
Не совсем, вы не сравниваете два значения, вы просто гарантируете, что они оба существуют, они разные.
Кирилл Н.

3
На самом деле он оценивает его так же, как javascript, с веб-сайта: «Вы можете использовать помощник if для условного рендеринга блока. Если его аргумент возвращает false, undefined, null,» »или [] (« ложное »значение), Рули не будут отображать блок. "
Джоно

1
Вы правы, я сначала подумал, что тест должен был сравнить два значения, а не тестирование обоих существовало. Мой плохой, извини.
Кирилл Н.

4
Это не работает правильно. Если cond1 имеет значение true, а con2 имеет значение false, ничего не будет напечатано.
Тесса Лау

1
Привет @TessaLau, я думаю, я вижу, откуда ты. Однако, если вы вытяните поток управления, вы увидите, что в самой первой строке поток управления переходит в это состояние.
Йоно

19

Одна проблема со всеми ответами, опубликованными здесь, заключается в том, что они не работают со связанными свойствами, т.е. условие if не переоценивается, когда изменяются соответствующие свойства. Вот немного более продвинутая версия помощника, поддерживающего привязки. Он использует функцию связывания из источника Ember, которая также используется для реализации обычного #ifпомощника Ember .

Это ограничено одним связанным свойством с левой стороны по сравнению с константой с правой стороны, что, на мой взгляд, достаточно для большинства практических целей. Если вам нужно что-то более сложное, чем простое сравнение, тогда, возможно, было бы хорошо начать объявлять некоторые вычисляемые свойства и использовать #ifвместо этого обычный помощник.

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

Вы можете использовать это так:

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

Это правильный ответ, если вы используете Ember. Другие решения, как вы упомянули, просто передадут ключ вместо значения. Кстати, спасибо за это, провел несколько часов, ломая мою голову.
Джей Ли

2
Кто-нибудь получил эту работу с HTMLBars / Ember 1.10? Ember.Handlebars.bind больше не существует.
Линда

Первоначально я использовал registerBoundHelper первоначально, но затем, когда он изменил условие, он не изменится на значение else и обратно. Этот метод работает с ember для изменения :) У него должно быть намного больше голосов
Мэтт Вукоманович,

13

Усовершенствованное решение, которое в основном работает с любым бинарным оператором (по крайней мере, числа, строки плохо работают с eval, БУДЬТЕ ОСТОРОЖНЫМ ВСТУПЛЕНИЕМ В СЦЕНАРИЙ, ЕСЛИ ИСПОЛЬЗУЯ НЕ ОПРЕДЕЛЕННЫЙ ОПЕРАТОР С ПОЛЬЗОВАТЕЛЯМИ)

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

как бы вы использовали это в шаблоне? особенно часть options.fn?
qodeninja

{{ifCond val1 '||' val2}} true {{else}} false {{/ if}} он возвращает options.fn (true, предложение ifCond), если он правильный, в противном случае он возвращает options.inverse (false, предложение else), если неверный.
Ник Китто

1
Из-за оговорки, упоминаемой о внедрении скрипта, я настоятельно рекомендую не использовать этот помощник. В большой кодовой базе это может быть легко ответственно за неприятную проблему безопасности в будущем
Джордан Ситкин

8

Вот решение, если вы хотите проверить несколько условий:

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

Применение:

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

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

7

Вот ссылка на хелпер блока, который я использую: хелпер блока сравнения . Он поддерживает все стандартные операторы и позволяет писать код, как показано ниже. Это действительно очень удобно.

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

1
Это должно быть победное голосование. Родной и предназначенный. Я почти каждый раз обнаруживаю, что если вы пишете нового помощника, вы слишком обдумываете его.
Авгурон

2
@augurone это не местный помощник. Если вы перейдете по ссылке, вы увидите, что это пользовательский помощник.
gfullam

@gfullam Вы правы, я использовал руль в ассемблере, который изначально содержит этот помощник. Виноват.
Авгурон

4

Подобно ответу Джима, но используя немного творчества, мы могли бы сделать что-то вроде этого:

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

Затем, чтобы использовать его, мы получаем что-то вроде:

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

Я бы посоветовал убрать объект из функции для повышения производительности, но в противном случае вы можете добавить любую функцию сравнения, какую хотите, включая «и» и «или».


3

Еще одна альтернатива - использовать имя функции в #if. Он #ifобнаружит, является ли параметр функцией, и если это так, то вызовет его и использует свой возврат для проверки достоверности. Ниже myFunction получает текущий контекст как this.

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

Итак, вам нужно добавить функцию в контекст? Выполнение кода из контекста является дырой в безопасности, поскольку источник кода может быть неизвестен. Это может быть использовано для атаки XSS.
Т Нгуен

Да, вам нужно добавить функцию в контекст. Да, на плохо спроектированном веб-сайте это может быть дырой в безопасности. Но в этом случае было бы много других.
Шиталь Шах

Это предпочтительный способ .. TY.
elad.chen

3

К сожалению, ни одно из этих решений не решает проблему оператора «ИЛИ» cond1 || cond2 ".

  1. Проверьте, является ли первое значение истинным
  2. Используйте «^» (или) и проверьте, верно ли в противном случае cond2

    {{#if cond1}} ДЕЙСТВОВАТЬ {{^}} {{#if cond2}} ДЕЙСТВОВАТЬ {{/ if}} {{/ if}}

Это нарушает СУХОЕ правило. Так почему бы не использовать частичное, чтобы сделать его менее грязным

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

3

Я могу понять, почему вы хотели бы создать помощника для ситуаций, когда у вас есть большое количество различных сравнений для выполнения в вашем шаблоне, но для сравнительно небольшого числа сравнений (или даже одного, которое и привело меня на эту страницу в первое место), вероятно, было бы проще определить новую переменную handlebars в вызове функции визуализации вида, например:

Перейдите к рулю на рендере:

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

и затем в вашем шаблоне руля:

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

Я упоминаю об этом для простоты, а также потому, что это ответ, который может быть быстрым и полезным, но при этом соответствовать логике Руль.


3

Установите дополнение Ember Truth Helpers , выполнив следующую команду

ember install ember-true-helpers

Вы можете начать использовать большинство логических операторов (например, not-eq, not, и, или, gt, gte, lt, lte, xor).

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

Вы можете даже включить подвыражение, чтобы пойти дальше,

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

2

Еще одно кривое решение для троичного помощника:

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

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

Или простой помощник по объединению:

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

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

Поскольку эти символы не имеют особого значения в разметке руля, вы можете использовать их для имен помощников.


1

Я нашел пакет npm, сделанный с CoffeeScript, в котором есть много невероятно полезных помощников для Handlebars. Посмотрите документацию по следующему URL:

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

Вы можете сделать wget http://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.2.6.tgz скачать их и посмотреть содержимое пакета.

Вы сможете делать такие вещи, как {{#is number 5}}или{{formatDate date "%m/%d/%Y"}}


1

если вы просто хотите проверить, присутствует ли тот или иной элемент, вы можете использовать этот пользовательский помощник

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

нравится

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

если вам также нужно иметь "или" для сравнения возвращаемых значений функции я бы лучше добавил другое свойство, которое возвращает желаемый результат.

Шаблоны должны быть без логики в конце концов!



1

Только что пришел к этому сообщению из поиска Google о том, как проверить, равна ли строка другой строке.

Я использую HandlebarsJS в NodeJS на стороне сервера, но я также использую те же файлы шаблонов на внешнем интерфейсе, используя версию HandlebarsJS для браузера для его анализа. Это означало, что если бы мне нужен пользовательский помощник, мне пришлось бы определять его в двух разных местах или назначать функцию для рассматриваемого объекта - слишком много усилий !!

Люди забывают, что некоторые объекты имеют наследуемые функции, которые можно использовать в шаблоне усов. В случае строки:

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.

Мы можем использовать этот метод для возврата либо массива совпадений, либо nullесли совпадений не найдено. Это прекрасно, потому что, глядя на документацию 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.

Так...

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

ОБНОВИТЬ:

После тестирования во всех браузерах это не работает в Firefox . HandlebarsJS передает другие аргументы в вызов функции, что означает, что при вызове String.prototype.match второй аргумент (т. Е. Флаги Regexp для вызова функции match в соответствии с приведенной выше документацией), по-видимому, передается. Firefox рассматривает это как устаревшее использование String.prototype.match, и поэтому ломает.

Обходной путь - объявить новый функциональный прототип для объекта String JS и использовать его вместо этого:

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

Убедитесь, что этот код JS включен, прежде чем запускать функцию Handlebars.compile (), а затем в шаблон ...

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

Обновлено для Firefox, это то, что я сейчас использую
Jon

1

Здесь у нас есть ванильные рули для нескольких логических && и || (и или):

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

Не уверен, что «безопасно» использовать «и» и «или» ... может быть что-то вроде «op_and» и «op_or»?


1

Правильное решение для И / ИЛИ

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

Затем позвоните следующим образом

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

Кстати: обратите внимание, что приведенное здесь решение неверно, он не вычитает последний аргумент, который является именем функции. https://stackoverflow.com/a/31632215/1005607

Его оригинальное И / ИЛИ было основано на полном списке аргументов

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

Может кто-нибудь изменить этот ответ? Я просто потратил впустую час, пытаясь что-то исправить в ответе, рекомендованном 86 людьми. Исправление состоит в том, чтобы отфильтровать последний аргумент, который является именем функции.Array.prototype.slice.call(arguments, 0, arguments.length - 1)


0

Следуя этим двум руководствам: « способ-позволить-пользователям-определить-пользователь-сделал-----------------в-в» и хелперы с настраиваемыми привязками, я смог настроить мои общие представления в этом посте на stackoverflow, чтобы использовать его вместо стандартного # если заявление. Это должно быть более безопасно, чем просто бросить туда #if.

Помощники по обычаю в этой сути выдающиеся.

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

Я использую Ember Cli для создания своего приложения ember.

Текущая настройка на момент публикации:

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

В Ember.js вы можете использовать inline if helper в if block helper. Он может заменить ||логический оператор, например:

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

0

Вы можете сделать это просто используя логический оператор, как показано ниже:

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

Перед закрытием, если вы можете написать свою бизнес-логику


0

Вы можете использовать следующий код:

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

Пожалуйста, объясните больше о ваших мыслях и процессе, людям может быть очень трудно понять ваше решение, если они не знают контекста или плохо знакомы с языком.
mrhn

-1

Вот подход, который я использую для ember 1.10 и 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));
});

Затем вы можете использовать его в своих шаблонах, как это:

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

Где аргументы выражения передаются как p0, p1и p2т. Д., И на них p0также можно ссылаться как this.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.