2016-07-01 3 views
1

В течение нескольких дней я начал использовать Ручки, и сейчас я использую Decorators. Я понял, как это работает, когда оно остается простым: Ex: украсить имя в одиночку: bill gaTes -> Mr Bill GATESДекоратор ручек в петле

Затем я попытался использовать декоратор в цикле «каждый», чтобы сделать то же самое, что и раньше, но со списком людей вместо одного. Проблема в том, что, когда я нахожусь в функции декоратора, мне нужно знать, какой элемент (из массива) я просматриваю.

Поэтому я хотел бы либо указать аргумент индекса цикла «каждый» (тогда, поскольку у меня есть доступ к данным, я мог бы получить текущий элемент) или текущий элемент.

Я попытался использовать @index (который обычно работает хорошо), но при отладке я получаю undefined. И я не могу найти способ получить текущий элемент в моем декораторе.

Вот код:

index.html

<!doctype html> 
<html> 
    <head> 
     <title>Test Handlebars Decorators 4</title> 
    </head> 
    <body> 
     <div id = "main"> </div> 

     <script id = "rawTemplate" type = "text/x-handlebars-template"> 

      {{#each this}} 
       Decorated: {{formatGenderHelper this}} 
       {{* activateFormatter @index}} 
       <br /> 
      {{/each}} 

     </script> 

     <script type = "text/javascript" src = "js/lib/handlebars.min-latest.js"></script> 
     <script type = "text/javascript" src = "js/lib/jquery-2.2.4.min.js"></script> 
     <script type = "text/javascript" src = "js/data.js"></script> 
     <script type = "text/javascript" src = "js/index.js"></script> 
    </body> 
</html> 

data.js

var data = [{ 
    "firstname": "Bill", 
    "lastname": "Gates", 
    "gender": "MALE" 
}, { 
    "firstname": "Hillary", 
    "lastname": "Clinton", 
    "gender": "FEMALE" 
}]; 

function formatMale(author) { 
    return "M. " + author.firstname + " " + author.lastname.toUpperCase(); 
} 
function formatFemale(author) { 
    return "Mme " + author.firstname + " " + author.lastname.toUpperCase(); 
} 

Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) { 
    var genderHelper; 
    var gender = context.args[0] || context.data.root[0].gender; 

    switch(gender) { 
     case "MALE": 
      genderHelper = formatMale; 
      break; 
     case "FEMALE": 
      genderHelper = formatFemale; 
      break; 
     default: 
      console.log('Gender format not set. Please set before rendering template.'); 
      genderHelper = function() {}; 
    } 

    container.helpers = { 
     formatGenderHelper: genderHelper 
    }; 
}); 

index.js

// Get the template 
var rawTemplate = $('#rawTemplate').html(); 

// Compile the template 
var compiledTemplate = Handlebars.compile(rawTemplate); 

// Apply the template on the data 
var content = compiledTemplate(data); 

// Finally, re-inject the rendered HTML into the DOM 
$('#main').html(content); 

Если вам нужна дополнительная информация, пожалуйста, дайте мне знать.

Спасибо за помощь :)

+0

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

+0

Не могли бы вы немного расширить свой смысл? – Barudar

+0

@ Барудар декоратор запускается одновременно с родительским блоком, а не дочерним блоком, где находится декоратор. Таким образом, это несколько нарушает типичные рассуждения о порядке выполнения блоков в шаблоне. В практическом плане для вашего случая, приведенного выше, это означает, что он запускается один раз, чтобы настроить функцию форматирования для всего родительского '# each' блока, а не для каждого дочернего блока, созданного' # each', итерации через элементы. –

ответ

2

Есть два вопроса, которые делают ваш пример не в состоянии. Один из них - небольшая проблема с вашим кодом, а другой - способ, которым, похоже, работают декораторы, которые по сути являются «не в циклах» (если вы не используете частичные, см. Последний раздел этого ответа).


Во-первых, вы не сказали декоратор, что делать с @index, что вы передаете ему. Вы можете изменить функцию декоратора, но так как у вас есть декоратор внутри блока #each, this является тем же самым, который передается formatGenderHelper, что означает, что мы можем передать декоратор this.gender, который разрешает только гендерную строку. Это означает, что автор шаблона точно знает, что они передают декоратору, и логика не пытается вторгаться в то, что говорит этот шаблон.

index.html

... 
{{#each this}} 
    Decorated: {{formatGenderHelper this}} 
    {{* activateFormatter this.gender}} 
    <br /> 
{{/each}} 
... 

Also, I figure you are basing your example on Ryan Lewis's sitepoint demo . One problem/limitation his code has that isn't immediately obvious (because in the simple case it isn't even an issue), is that his decorator overwrites of all of the available helpers except for the formatting one it provides. To avoid "Error(s): TypeError: Cannot read property 'call' of undefined" errors when doing things that are a little bit more complex, I recommend using this in your decorator function.

data.js

Handlebars.registerDecorator('activateFormatter', function(program, props, container, context) { 
     // leaving out the code here for brevity 
     container.helpers = Object.assign({}, container.helpers, { 
      formatGenderHelper: genderHelper 
     }); 
    }); 

Второй вопрос является общим с помощью декораторов в петлях, то есть просто результат пути Рули работает с декораторами.Согласно decorators API doc,

Decorators are executed when the block program is instantiated and are passed (program, props, container, context, data, blockParams, depths).

Это означает (AFAICT), что, когда шаблон для блока первым реализованным, имея в виду, прежде чем любой из других помощников или программ, которые должны будут работать на блоке, он выполняет декоратора , а декоратор внесет необходимые изменения, перед выполнением программы, которая создала блок (в данном случае #each). Это означает, что для того, чтобы заставить декоратора различать каждую итерацию #each по-разному, он должен запускаться в блоке внука #each, поэтому он выполняется после #each, но до formatGenderHelper, однако, если вы это делаете и переопределяете декорированное помощник с каждой итерации на основе контекста итеративно-над, вы лучше просто зарегистрировав помощник, который имеет логику пол форматирования запеченный в.


Однако, это своего рода не-ответа. Итак, чтобы ответить на ваш вопрос, я обнаружил, что вы может сделать рули делать то, что вы пытаетесь сделать, но это своего рода хак. Поскольку трюк заключается в том, что вам нужен блок с декоратором, который будет отображаться из суб-субблока #each, мы можем отобразить его в частичном. Чтобы сделать это, мы можем вставить его в другой файл и зарегистрировать это как частичное, но это не очень удобно, поэтому у нас есть два лучших варианта. 1) мы можем обернуть код в неопределенном частичном блоке и позволить Handlebars отображать его как резервный блок, когда этот частичный сбой, или (опция slicker) 2) мы можем использовать предоставленный встроенный декоратор #*inline для определения встроенного частичного.

  1. отказоустойчивость методом частичного блока

    index.html

    ... 
    {{#each this}} 
        {{#>nothing}} 
         Decorated: {{formatGenderHelper this}} 
         {{* activateFormatter this.gender}} 
         <br /> 
        {{/nothing}} 
    {{/each}} 
    ... 
    
  2. #*inline метод

    index.html

    ... 
    {{#*inline "formattedAuthor"}} 
        Decorated: {{formatGenderHelper this}} 
        <br /> 
    {{/inline}} 
    {{#each this}} 
        {{#>formattedAuthor}} 
         {{* activateFormatter this.gender}} 
        {{/formattedAuthor}} 
    {{/each}} 
    ... 
    

Ключевым моментом здесь является то, что мы используем *activeFormatter декоратора, чтобы динамически переконфигурировать парциальное каждый раз, когда она вызывается. Второй пример inline демонстрирует это более четко. Разумеется, могут быть и другие хорошие варианты использования, но именно здесь я вижу, что декораторы действительно сияют, то есть позволяют нам динамически перенастраивать логику или помощники парциальных чисел прямо с того места, где мы называем их.

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

+0

Здравствуйте, Возможно, вы долго писали все это. Кроме того, это очень хорошо объяснено, спасибо за это. Я лучше понимаю, как работают декораторы. Мне все еще нужно копать немного больше о том, как они должны использоваться. И оба примера работают как шарм. Так что спасибо за это! – Barudar

+0

Только один вопрос: в предпоследнем абзаце вы сказали «* activeTranslator». Вы имели в виду "* activateFormatter" или я что-то пропустил? – Barudar

+0

Hah! Ты поймал меня! Я разработал ответ на этот вопрос для аналогичной проблемы с активным помощником перевода, чтобы сделать интернационализацию для наших шаблонов электронной почты :) Я сделаю редактирование в своем ответе –

Смежные вопросы