Returning subdocument array through Meteor / Mongo
Asked Answered
M

2

1

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);
Mezzo answered 14/1, 2015 at 19:43 Comment(3)
Could you provide a schema of an item then?Thumbnail
Sure thing - added to the original post.Mezzo
Also, have you tried Items.find({}); in your itemTags helper as well as referencing this in your template, such as this.itemText, instead of {{itemTag}}?Manifestation
D
2

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.

Druce answered 14/1, 2015 at 22:54 Comment(2)
Wow - thanks! Turns out it wasn't the template helper being incorrectly written. It needed to be deleted altogether, as I already had a template helper on my items template pulling the returns. After deleting that helper and changing to {{this}} it works perfectly. Appreciate all the help!Mezzo
No problem, glad you've worked it. In theory, you can just print an array on the page as {{itemTags}} and in the background, its toString() method gets returned, so values separated by commas. But then there is no way to provide a dom (like lists) or style them individually, or events etc. Anyway, good lock on the whole proect! :)Druce
M
0

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");
Manifestation answered 14/1, 2015 at 22:37 Comment(1)
Yup, I was able to see all my items and manipulate them with their modification functionality, but I simply couldn't get the tags to appear on them.Mezzo

© 2022 - 2024 — McMap. All rights reserved.