[javascript] handlebars.js {{#if}}의 논리 연산자 조건부

핸들 바 JS에서 논리 연산자를 표준 handlebars.js 조건부 연산자에 통합하는 방법이 있습니까? 이 같은:

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

나는 내 자신의 도우미를 쓸 수 있다는 것을 알고 있지만 먼저 바퀴를 재발 명하지 않도록하고 싶습니다.



답변

이것은 블록 도우미로 ‘속임수’를 사용하여 가능합니다. 이것은 아마도 핸들 바를 개발 한 사람들의 이념에 위배됩니다.

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


답변

솔루션을 한 단계 더 발전시킵니다. 비교 연산자가 추가됩니다.

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


답변

핸들은 중첩 작업을 지원합니다. 논리를 조금 다르게 작성하면 유연성이 향상되고 코드가 깨끗해집니다.

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


답변

가장자리에 사는 당신을 위해 이것을 한 단계 끌어 올리십시오.

요점 : https://gist.github.com/akhoury/9118682
데모 : 아래 코드 스 니펫

핸들 바 도우미 : {{#xif EXPRESSION}} {{else}} {{/xif}}

식으로 IF 문을 실행하는 도우미

  1. EXPRESSION은 올바르게 이스케이프 된 문자열입니다.
  2. 예 당신이 필요해 제대로 문자열 리터럴하거나 다른 단일 및 이중 따옴표를 탈출
  3. 모든 글로벌 기능이나 속성에 액세스 할 수 있습니다. encodeURIComponent(property)
  4. 이 예제는 당신이 당신의 핸들이 컨텍스트를 통과 가정 template( {name: 'Sam', age: '20' } ), 통지 ageA는 string내가 데모를 할 수 너무 들어, parseInt()이 게시물의 뒷부분

용법:

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

산출

<p>
  BOOM
</p>

자바 스크립트 : (다른 도우미에 따라 다름)

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

핸들 바 도우미 : {{x EXPRESSION}}

자바 스크립트 표현식을 실행하는 도우미

  1. EXPRESSION은 올바르게 이스케이프 된 문자열입니다.
  2. 예 당신이 필요해 제대로 문자열 리터럴하거나 다른 단일 및 이중 따옴표를 탈출
  3. 모든 글로벌 기능이나 속성에 액세스 할 수 있습니다. parseInt(property)
  4. 이 예제를 사용하면 핸들이 컨텍스트를 통과 가정 template( {name: 'Sam', age: '20' } ), ageA는 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>

자바 스크립트 :

구문을 확장하고 명확성을 위해 거의 각 줄에 주석을 달았 기 때문에 약간 커 보입니다.

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

자바 스크립트 :

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


답변

도우미 함수를 작성하지 않고이 작업을 수행하는 간단한 방법이 있습니다. 템플릿 내에서 완전히 수행 할 수 있습니다.

{{#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와 같은)는 true로 계산되지 않습니다.


답변

여기에 게시 된 모든 답변의 한 가지 문제는 바인딩 된 속성, 즉 속성이 변경 될 때 if 조건이 다시 평가되지 않는다는 것입니다. 바인딩을 지원하는 도우미의 약간 더 고급 버전이 있습니다. Ember 소스 의 바인드 기능을 사용하는데, 이는 일반적인 Ember #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}}


답변

기본적으로 모든 이항 연산자와 함께 작동하는 개선 된 솔루션 (최소한 숫자, 문자열은 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);
    }
});