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 に答える