4

摘要:
嵌套在父类别中的子类别不会在 Meteor 模板中呈现。

详细信息:
考虑“类别”的数据模型,如下所示:

// Model Schema
Category {
   idCategory : 20, (id of the category itself)
   idCategoryParent : 0, (idCategory of our parent category)
   defaultLabel : "Movies" (our label)
}

有父类和子类。父类别的 idCategoryParent 属性值为 0。子类别将其父类别的 idCategory 存储为其 idCategoryParent 属性。我正在尝试遍历这些类别的集合并以下列方式呈现它们:

<b>Movies</b> // parent category is in bold
<ul> // child categories are rendered as an unordered list
  <li>Horror</li> 
  <li>Comedy</li>
  <li>Action</li>
  <li>Drama</li>
</ul>

<b>Music</b>
<ul>
  <li>Rock</li> 
  <li>Classical</li>
  <li>Ambient</li>
</ul>

但是,这是我实际得到的:

<b>Movies</b>
<ul> // empty...
</ul>

<b>Music</b>
<ul>
</ul>

源代码:

// How we get the 'categories_parents' data
Template.content.categories_parents = function (){ 

    /*
    * Get all parent categories (categories with an idCategoryParent of 0)
    */
    var parents = Categories.find({idCategoryParent:0});
    var pCount = parents.count();

    for (var i = 0; i < pCount; i++){

            var pId = parents.db_objects[i]['idCategory'];
            /* 
            * Get all child categories of the parent (categories with
            * an idCategoryParent equal to value of parent category's idCategory).
            */
            var children = Categories.find({idCategoryParent:pId});
            var cCount = children.count();

            /*
            * Assign the child categories array as a property of the parent category
            * so that we can access it easily in the template #each expression
            */
            parents.db_objects[i]['children'] = children;
    }

    return parents;
}


// This is our template
<template name="content">
<h1>Categories</h1>
    {{#each categories_parents}}
        <b>{{defaultLabel}}</b><br />
        <ul>
            {{#each children}}
            <li>{{defaultLabel}}</li>
            {{/each}}
        </ul>
    {{/each}}
</template>

我在故障排除中尝试过的其他模板配置:

{{#each children}}
<li>A Child Exists Here</li> // Even this never rendered... no children?
{{/each}}

任何关于为什么会发生这种情况的线索将不胜感激。

4

3 回答 3

15

你的模型有点不确定......考虑一下

{name:"Category name", parent:"_id of parent category"}

好的,这要简单得多。创建一个类别。

var moviesId = Categories.insert({name:"Movies"});
Categories.insert({name:"Horror",parent:moviesId});

这很容易。现在,以一种有效的方式渲染{{#each}}

Template.categories.categories = function(parent) {
  if (parent) {
    return Categories.find({parent:parent}).fetch();
  } else {
    return Categories.find({parent:{$exists:false}});
  }
}

你可能会看到这是怎么回事......

<template name="categories">
   {{#each categories}}
   <ul>{{name}}
       {{#each categories _id}}
          <li>{{name}}</li>
       {{/each}}
   </ul>
   {{/each}}
</template>

现在我不确定{{#each}}块助手在调用另一个助手时是否可以接受函数参数。如果没有...

Template.categories.categories = function() {
  return Categories.find({parent:{$exists:false}}).map(function(parentCategory) {
    return _.extend(parentCategory,
                    {children:Categories.find({parent:parentCategory._id}).fetch()});
  }); 
}

这是一个真正的笨蛋。它返回具有新“子”列表属性的父类别,其中包含所有子类别。现在你可以这样做:

<template name="categories">
   {{#each categories}}
   <ul>{{name}}
       {{#each children}}
          <li>{{name}}</li>
       {{/each}}
   </ul>
   {{/each}}
</template>

聪明,嗯?

于 2012-12-13T09:19:54.807 回答
0

我不知道 db_objects,当我尝试访问游标上的该属性(这是find()返回的)时,它是null.

您可以改为获取与您的查询匹配的项目,然后进行迭代:

Template.content.categories_parents = function (){ 

    var parents = Categories.find({idCategoryParent:0}).fetch(); // Returns an array.

    for (var i = 0; i < parents.length; i++){

        var pId = parents[i]['idCategory'];

        var children = Categories.find({idCategoryParent:pId});

        // No need for array here, cursor is fine.
        parents.db_objects[i]['children'] = children; 
    }

return parents;
}

我自己是新手,所以也许有一种更有效的方法,但我目前不知道。

埃里克评论后更新。

js 文件如下所示:

Categories = new Meteor.Collection("categories");

if (Meteor.isClient) {
    Template.categories.categories = function () {
        var parents = Categories.find({idCategoryParent:0}).fetch();

        for (var i = 0; i < parents.length; i += 1) {
            var pId = parents[i]['idCategory'];

            var children = Categories.find({idCategoryParent:pId});

            parents[i]['children'] = children;

        }
        return parents;
    };
}

if (Meteor.isServer) {
    Meteor.startup(function () {
        Categories.remove({});
        var data = [
            {idCategoryParent: 0, idCategory: 1, label: "Movies"},
            {idCategoryParent: 1, idCategory: 0, label: "Science Fiction"},
            {idCategoryParent: 1, idCategory: 0, label: "Drama"},

            {idCategoryParent: 0, idCategory: 2, label: "Music"},
            {idCategoryParent: 2, idCategory: 0, label: "Jazz"},
            {idCategoryParent: 2, idCategory: 0, label: "Piano"}
          ];

        for (var i = 0; i < data.length; i += 1) {
            Categories.insert(data[i]);
        }
  });
}

html 文件如下所示:

<head>
  <title>nested_template</title>
</head>

<body>
  {{> categories}}
</body>

<template name="categories">
    <h1>Categories</h1>
    {{#each categories}}
        <b>{{label}}</b>
        <ul>
        {{#each children}}
            <li>{{label}}</li>
        {{/each}}
        </ul>
    {{/each}}
</template>

它对我来说很好用。

于 2012-12-06T20:56:14.980 回答
-1

解决了。

我的解决方案是从模板中删除 {{#each}} 逻辑并将其替换为单个把手帮助器表达式,然后一次性传回所需的 html。html 是从 Categories 集合的光标中的数据生成的。

不过,我不太确定在我的逻辑中包含所有这些 html - 这是糟糕的设计吗?如果是这样,我将遵循更好的答案。

// This is the new template
<template name="content">
<h1>Categories</h1>
    {{listCategories}}
</template>



// Handlebars helper 
Handlebars.registerHelper('listCategories', function() {

  var parents = Categories.find({idCategoryParent:0});
  var countParents = parents.count();
  var string = '';

  // iterate over each parent category  
  for(m = 0; m < countParents; m++){

      // Get the parents category id
    var pId = parents.db_objects[m].idCategory;
    var children = Categories.find({idCategoryParent:pId});
    var count = children.count();

      /*
      * Build the Parent Category html
      * Example: <b>Movies</b><ul>
      */
    string = string + '<b>' + parents.db_objects[m].defaultLabel + '</b><ul>';

    // iterate over each child category
    for(var i = 0; i < count; i++){

         /*
         * Build the child category html
         * Example: <li>Horror</li>
         */
       string = string + '<li>' + children.db_objects[i]['defaultLabel'] + '</li>';
    }

      // Close up the unordered list
    string = string + '</ul>';

  }

  // Return the string as raw html
  return new Handlebars.SafeString(string);

});



// Rendered out the result correctly like so:
<b>Movies</b>
<ul>
  <li>Horror</li> 
  <li>Comedy</li>
  <li>Action</li>
  <li>Drama</li>
</ul>

<b>Music</b>
<ul>
  <li>Rock</li> 
  <li>Classical</li>
  <li>Ambient</li>
</ul>
于 2012-12-09T15:18:20.767 回答