简体   繁体   中英

Returning subdocument array through Meteor / Mongo

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);

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.

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");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM