翻译Handlebars使用结束标签阻止助手进入Meteor?

时间:2014-08-30 16:03:55

标签: meteor handlebars.js

在Meteor中,我有一个应用程序,我在其中列出按标签分组的项目,其中未标记的项目首先出现,然后标记的项目隐藏在“标记标题”下拉列表中。

我没有碰过这个应用程序,因为0.8出来了,我在一个模板中使用了一个块帮助器,在0.8之前工作正常......

See working jsfiddle here

Handlebars.registerHelper('eachItem', function(context, options) {
  var ret = "";

  for(var i=0, j=context.length; i<j; i++) {
      if(!context[i].tag){
         ret = ret + options.fn(context[i]);
      } else {
          if(i===0||!context[i-1].tag ||context[i-1].tag !== context[i].tag){

             ret = ret + '<li class="list-group-item"><a data-toggle="collapse" data-target="#'+ context[i].tag +'"> Items tagged  '+context[i].tag + '</a></li><div id="'+context[i].tag+'" class="collapse">';
          }
          ret = ret + options.fn(context[i]);

          if(i+1<j && context[i+1].tag !== context[i].tag){
              ret = ret + '</div>';
          }
      }
  }
  return ret;
});

但我有点挣扎到translate this into post-0.8 Meteor

The inserted HTML must consist of balanced HTML tags. You can't, for example, 
insert "    </div><div>" to close an existing div and open a new one.

我的一个想法是在一个vanilla {{#each}}循环(带有两个不同的模板)中呈现未标记的项目和容器,然后执行类似的操作

Template.myListContainer.rendered = function(){
    _.each(tags, function(tag){
        var tagged_items = _.filter(items, function(item){ return item.tag == tag; });
        _.each(tagged_items, function(item){
            UI.insert(UI.RenderWithData(listItemTemplate, { item : item }), tagContainer);
        });
    });
}

有更简单的方法吗?如果物品来自集合,他们会保持反应吗? 非常感谢提前!

2 个答案:

答案 0 :(得分:1)

如果您还没有,那么值得阅读Meteor wiki on migrating to blaze.

无论如何,这个似乎很难实现直接迭代。

如果您按特定顺序需要它们,我只会列出w /和w / o标签的项目,例如:

Template.example.helpers({
  dataWithoutTags: function(){
    return items.find({tag:{exists: false}});
  },
  tagList: function(){
    // create a distinct list of tags
    return  _.uniq(items.find({tag:{exists: true}}, {tag: true}));
  },
  dataForTag: function(){
    // use `valueOf` as `this` is a boxed-string
    return items.find({tag: this.valueOf()});
  }
});

模板:

<template name="example">
  <div class='panel panel-default'>
  <ul class='list-group'>
      {{#each dataWithoutTags}}
        <li class='list-group-item'>{{name}}</li>
      {{/each}}
      {{#each tagList}}
        <li class="list-group-item">
          <a data-toggle="collapse" data-target="#{{this}}"> Items tagged  {{this}}</a>
        </li>
        <div id="{{this}}" class="collapse">
          {{#each dataForTag}}
              <li class='list-group-item'>{{name}}</li>
          {{/each}}
        </div>
      {{/each}}
  </ul>
  </div>
</template>

如果你需要按特定顺序 - 例如。 仅对连续项目进行分组(根据您的示例)。唯一的选择是预处理它们。

例如:

Template.example.helpers({
  itemsGrouped: function(){
    dataGroups = [];
    currentGroup = null;
    items.find({}, {sort: {rank: 1}}).forEach(function(item){
      if (currentGroup && (!item.tag || currentGroup.tag != item.tag)){
          dataGroups.push(currentGroup);
          currentGroup = null;
      } 
       if (item.tag){
          if (!currentGroup){
            currentGroup = {
              group: true,
              tag: item.tag,
              items: [item]
            };
          } else {
            currentGroup.items.push(item);
          }
       } else {
          dataGroups.push(item);
       }
    });
    if (currentGroup){ dataGroups.push(currentGroup); }
    return dataGroups;
  }
});

模板:

<template name="example">
  <div class='panel panel-default'>
  <ul class='list-group'>
      {{#each itemsGrouped}}
        {{#if group}}
            <li class="list-group-item">
              <a data-toggle="collapse" data-target="#{{tag}}"> Items tagged  {{tag}}</a>
            </li>
            <div id="{{tag}}" class="collapse">
              {{#each items}}
                  <li class='list-group-item'>{{name}}</li>
              {{/each}}
            </div>
        {{else}}
          <li class='list-group-item'>{{name}}</li>
        {{/if}}
      {{/each}}
  </ul>
  </div>
</template>

答案 1 :(得分:0)

如果您记录从eachItem帮助程序返回的值,您将看到没有关闭最后一个div元素。修复可能会让它再次运行。但是,您有div个元素作为ul元素的直接子元素,您不应该according to the HTML5 specification

  

允许的内容:零个或多个li元素

另外,我认为以更简单的模板处理渲染的格式准备上下文是一个更好的选择。例如,使用jsfiddle中的相同数据,假设您使用以下格式:

tagGroups = [{
  names: ["item1", "item2"]
},{
  tag: "red",
  names: ["item3", "item4"]
},{
  tag: "blue",
  names: ["item5", "item6", "item7"]
}]

以下模板将以有效的html格式为您提供预期结果。最终结果是一个包含可折叠列表组的引导程序面板:

<template name="accordion">
  <div class="panel panel-default">
    {{#each tagGroups}}
      {{> tagGroup}}
    {{/each}}
  </div>
</template>

<template name="tagGroup">
  {{#if tag}}
    {{> namesListCollapse}}
  {{else}}
    {{> namesList}}
  {{/if}}
</template>

<template name="namesList">
  <ul class="list-group">
    {{#each names}}
      <li class="list-group-item">{{this}}</li>
    {{/each}}
  </ul>
</template>

<template name="namesListCollapse">
  <div class="panel-heading"><a data-toggle="collapse" data-target="#{{tag}}">Items tagged {{tag}}</a></div>
  <ul id="{{tag}}" class="panel-collapse collapse list-group">
    {{#each names}}
      <li class="list-group-item">
        {{this}}
      </li>
    {{/each}}
  </ul>
</template>

以下是一个帮助您转换数据的示例,以便您可以快速进行测试,看看它是否有效:

Template.accordion.tagGroups = function () {

    var data =  [{
      name : 'item1'
    },{
      name : 'item2'
    },{
      name : 'item3',
      tag : 'red'
    },{
      name : 'item4',
      tag : 'red'
    },{
      name : 'item5',
      tag : 'blue'
    },{
      name : 'item6',
      tag : 'blue'
    },{
      name : 'item7',
      tag : 'blue'
    }];

    data = _.groupBy(data, 'tag');

    data = _.map(data, function (value, key) {
      var obj = {};

      if (key !== 'undefined') {
        obj.tag = key;
      }

      var names = _.map(value, function (item) {
        return item.name;
      });
      obj.names = names;

      return obj;
    });

    //console.dir(data);
    return data;
  };

是的,如果这些物品来自一个集合,您将默认获得反应。