Логічний оператор у handlebars.js {{# #f)} умовний


479

Чи є спосіб у рульовій JS включити логічні оператори до стандартного умовного оператора handlebars.js? Щось на зразок цього:

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

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

Відповіді:


518

Це можливо шляхом «обману» з помічником блоку. Це, мабуть, суперечить Ідеології людей, які розробляли руль.

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 1.0.0-rc.8 та Handlebars 1.0.0) і registerBoundHelperне може мати справу з синтаксисом Handlebars. Вирішення проблеми полягає у створенні спеціального перегляду: stackoverflow.com/questions/18005111/…
Warren Seine

28
@BalaClark чи справді це logicless? Я маю на увазі, що все ще є твердження «якщо» - тільки тому, що вони навмисно каліки не змінює філософію.
фрікхед

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

36
Я не розумію, чому І / АБО не може бути частиною кермів. Він не йде проти logicless природи , так як немає вже І.Ф., ПОКИ, і КОЖЕН ... так багато для logicless
Асаф

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

Версія сценарію кави

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
Бути noob для рульової панелі - одне, що було не зрозуміло - це те, що ви повинні передавати оператора як рядок, інакше компілятор помилиться під час токенізації вашого шаблону. {{#ifCond true '==' false false}}
Джо Холлоуей

2
Я знайшов значення, які не оцінюються для атрибутів об'єкта. Додавання наступної v1 = Ember.Handlebars.get(this, v1, options) v2 = Ember.Handlebars.get(this, v2, options)
допомоги

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

3
Чи можете ви зробити ще щось, якщо з цим?
jbyrd

160

Руль підтримує вкладені операції. Це забезпечує велику гнучкість (і чистіший код), якщо ми пишемо свою логіку трохи інакше.

{{#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 у Ембер 1.10. Крім того, ці помічники можуть бути доповненням Ембер CLI, якщо ви хочете: github.com/jmurphyau/ember-truth-helpers .
stephen.hanson

1
Таким чином, без optionsвиконання краще дотримуватися ifметоду і простіше перевірити. Дякую!
Вашингтон Ботелхо,

25
Ми, здається, вбудували Lisp в рулі.
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. ЕКСПРЕССІЯ - це правильно уникнута струна
  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. ЕКСПРЕССІЯ - це правильно уникнута струна
  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>

Моар

якщо ви хочете отримати доступ до верхнього рівня, цей дещо інший, вираз - СПОЛУЧЕННЯ всіх аргументів, використання: скажімо, контекстні дані виглядають так:

// 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
:) дякую, я трохи оновив суть, щоб додати ще декілька смаколиків (не пов’язаних безпосередньо з цим питанням ТАК - але в дусі робити те, що ви хочете всередині шаблону рулі). Однак, слідкуйте за обмеженнями, у мене немає Я не знайшов способу отримати доступ до "верхніх рівнів області" з виразу, скажімо, ви знаходитесь у кожному діапазоні, {{#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 для умовного відтворення блоку. Якщо його аргумент повертає хибне, невизначене, null, "" або [] ("фальшиве" значення), то будь-який "cond" (як cond1 або cond2) не вважатиметься істинним.


9
Насправді ви не порівнюєте двох значень, ви просто переконайтесь, що вони існують, це різне.
Кирило Н.

3
Насправді він оцінює це так само, як робить і javascript з веб-сайту: "Ви можете використовувати помічник if для умовного візуалізації блоку. Якщо його аргумент повертає false, undefined, null," "або [] (" фальшиве "значення), Ручки не візуалізують блок. "
Jono

1
Ви маєте рацію, по-перше, я вважав, що тест - порівняння двох значень, а не тестування обох. Мої погані, вибачте.
Кирило Н.

4
Це працює не правильно. Якщо cond1 вірно, а con2 - хибно, нічого не буде надруковано.
Тесса Лау

1
Гей, @TessaLau, я думаю, я бачу, звідки ти родом. Однак якщо ви намалюєте контрольний потік, ви побачите, що в першому рядку переміщується потік управління до цього стану.
Jono

19

Одна проблема з усіма відповідями, розміщеними тут, полягає в тому, що вони не працюють із пов'язаними властивостями, тобто умова if не переоцінюється при зміні відповідних властивостей. Ось дещо вдосконалена версія допоміжних вкладишів. Він використовує функцію прив'язки від джерела Ембер, яка також використовується для реалізації звичайного #ifпомічника Ембер .

Це обмежується однією обмеженою властивістю з лівого боку, порівняно з постійною з правого боку, що, на мою думку, є досить хорошим для більшості практичних цілей. Якщо вам потрібно щось більш досконале, ніж просте порівняння, то, можливо, було б добре почати декларувати деякі обчислювані властивості та використовувати #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, але потім, коли він змінив умову, він не змінився б на інше значення і назад .. Цей метод працює з Ембер для зміни :) У нього повинно бути набагато більше голосів
Метт Вукоманович

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 (вірно, пункт ifCond), якщо він правильний, в іншому випадку він повертає options.inverse (помилковий, інший пункт), якщо невірний.
Нік Кітто

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Виявить , якщо параметр є функцією і якщо після цього він буде викликати і використовувати його повернення для перевірки truthyness. Нижче myFunction отримує поточний контекст як this.

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

Тож вам потрібно було б додати функцію до контексту? Виконання коду з контексту є захисним отвором, оскільки джерело коду може бути невідомим. Це можна використати для нападу XSS.
T Nguyen

Так, вам потрібно додати функцію до контексту. На погано розробленому веб-сайті, так, це може бути дірка безпеки. Але в цьому випадку було б багато інших.
Shital Shah

Це кращий спосіб .. TY.
elad.chen

3

На жаль, жодне з цих рішень не вирішує завдання оператора "АБО" оператора "cond1 || cond2".

  1. Перевірте, чи є перше значення правдою
  2. Використовуйте "^" (або) і перевірте, чи не відповідає умові cond2

    {{#if cond1}} РОБІТЬ ДІЮ {{^}} {{#if cond2}} РОБІТЬ ДІЮ {{/ якщо}} {{/ якщо}}

Це порушує правило DRY. То чому б не використати часткове, щоб зробити його менш безладним

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

3

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

Перехід до рульової панелі при візуалізації:

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

а потім у шаблоні вашої ручки:

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

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


3

Встановіть додаток Ember Truth Helpers, виконавши команду нижче

ember встановити помічників правдивої правди

Ви можете почати використовувати більшість логічних операторів (eq, 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, який має безліч неймовірних корисних помічників для рульових панелей. Перегляньте документацію за такою 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 для виклику функції відповідності, як показано у вищезазначеній документації), здається, передається. 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') (..) ) }}

BTW: Зауважте, що наведене тут рішення є невірним, він не віднімає останній аргумент, який є ім'ям функції. https://stackoverflow.com/a/31632215/1005607

Його оригінальний AND / OR був заснований на повному переліку аргументів

   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

Виконуючи ці 2 настанови " шлях до дозволу" користувачам визначити-зроблено на замовлення "прив'язка-якщо-заяви" та призначені спеціальні помічники, я зміг налаштувати свої спільні погляди в цій публікації на 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, щоб створити свою програму.

Поточна настройка на момент публікації цієї публікації:

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

Це можна зробити просто за допомогою логічного оператора, як показано нижче:

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

Ось підхід, який я використовую для ембер 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.