Returning subdocument array through Meteor / Mongo

2019-08-10 03:49发布

I'm having a little trouble returning and displaying tags that I'm adding to a subdocument. I have no problem adding tags, but want to put a label on the item for each tag. I simply can't find a resource that helps me return the items in an array within a subdocument. I think it's all the helper where I'm stuck - basically the syntactically correct way to write "Items.(this._id).itemTags.find();" :)

Oh - and I've cut out a lot of the HTML and JS, but, yes, everything else is working fine. The collection is "Items" and the subdocument is "itemTags", set with "itemTags: []" during the insert. In my test environment I can add "Cats" and "Dogs" as tags and can verify it works by inspecting the objects through "Items.find().fetch();" but am struggling to display them.

HTML:

<template name="item">
  {{#each itemTags}}
    <span class="label label-default">{{itemTag}}</span>
  {{/each}}
</template>

JS:

Template.item.helpers({
   itemTags: function() {
    var currentUserId = Meteor.userId();
    return Items.find(); // yes, this line is completely wrong, but I'm lost hehe
  }
});

Template.item.events({
  'submit .add-tag': function(event) {
    event.preventDefault();

    var itemTag = event.target.text.value;

    Items.update(this._id, {$push: {itemTags: itemTag}});

    event.target.text.value = "";

    return false;
  }
});

Database schema (as shown by my insert command):

var item = {
  itemText: $(e.target).find('[name=itemText]').val(),
  createdAt: new Date(),
  createdBy: currentUserId,
  hard: false,
  difficulty: 'easy',
  checked: false,
  itemTags: [],
};

item._id = Items.insert(item);

2条回答
男人必须洒脱
2楼-- · 2019-08-10 04:13

Your only problem is trying to iterate a cursor and a sub array within the same each block. If you separate your items template and an individual item template, you'll end up with your desired result.

For the sake of simplification, I altered your code to look like this:

This is your main body:

<body>
    {{> items}}
</body>

<template name="items">
  {{#each items}}
    {{> item}}
  {{/each}}
</template>

<template name="item">
  <h2>{{itemText}} tags are:</h2>
  <ul>
  {{#each itemTags}}
    <li>{{this}}</li>
  {{/each}}
  </ul>
</template>

And this is your helper:

Template.items.helpers({
  items: function () {
    return Items.find();
  }
})

Assuming an item document looks like:

{ 
  itemText: String,
  itemTags: Array
}

I've created an app on Meteorpad for you to play with:

http://meteorpad.com/pad/BmRQ5fkwWEMBKszJW/SO-27951102

you can further alter the code there and see the changes in realtime. It is basically jsfiddle for meteor.

Edit: inspired by @chip-castle's comment, you can in fact use a single template with nested each blocks:

<template name="items">
  {{#each items}}
    <h2>{{itemText}} tags are:</h2>
    <ul>
    {{#each itemTags}}
      <li>{{this}}</li>
    {{/each}}
    </ul>
  {{/each}}
</template>

But using separate templates is more flexible in both design and handling events where necessary.

查看更多
Deceive 欺骗
3楼-- · 2019-08-10 04:24

Do you have a publication and subscription setup?

server/publications.js

Items = new Mongo.Collection("items");

Meteor.publish("items", function () {
  return Items.find({});
});

client/subscriptions.js

Items = new Mongo.Collection("items");

Meteor.subscribe("items");
查看更多
登录 后发表回答