Blaze problem - How can I show comments underneath their corresponding posts in template?

I had a working version which had comments as an array within the post document. But I couldn’t find a solution to update single elements of the array (couldn’t get the $ to work in $set) and so I decided to look how it was done in other apps like telescope.

They use both posts and comments in separate collections, so I decided to split mine as well. They are identified in the following way:

Posts are identified by a groupId

Comments are identified by a groupId but also directly linked to the correct Post by a postId and sorted by the created field to ensure that the comments are in the right chronological order after the comment.

Here’s the (relevant part of the) old html code when the comments was still in one collection with the posts:

{{#each posts}}
    {{name}}
    {{created}}
    {{text}}
    {{#if comments}}
        {{#each comments}}
            {{name}}
            {{created}}
            {{text}}
        {{/each}}  // of each comments
    {{/if}}
{{/each}}  // of each posts

Q1: How do I need to change this to reflect that they are now in two collections?

Q2: How can I ensure that the right comment is put under the corresponding post (not every post has a comment)?

Q3: Is it a good idea to use the same field names within the comments collection or shall I rather go for something like c_name, c_created and c_text instead?

Thanks you for your help, appreciated!

PS: I’m still learning Blaze and Frontend in general, hence my noob question

  1. it’s better to use each … in …, so you will be not confused with rewritten context.
    here:

    {{#each post in posts}}
    {{post.name}}
    {{post.created}}
    {{post.text}}
    {{#each comment in postComments post._id}}
    {{comment.name}}
    {{comment.created}}
    {{comment.text}}
    {{/each}} // of each comments
    {{/each}} // of each posts

Then you can create postComments helper like this (of course you need to subscribe to needed collections in template onCreate):

postComments(postId) {
    return Comments.find({postId: postId}, {sort: {created: -1}});
}
1 Like

@chipjuggler - thanks for your recommendations and tips. Please allow me to still ask some questions as not everything is clear to me.

  1. I currently use posts in the template helper, like this:

    Template.discuss.helpers ({
    posts: function (groupId) {

I assume this is wrong, I should use post: function (groupId) instead?

  1. Do you suggest to build a separate template for the comments part? That would make the Posts template less convoluted.

  2. As for the helper, shouldn’t the code rather be:

    Template.discuss.helpers ({
    postComments: function (postId) {
    ‘use strict’;
    return Comments.find({ postId: postId }, { sort: {created: -1} });
    },
    // followed by other like posts: function (groupId) {
    });

  3. My previous question, is it ok to use the same variable names in comments and posts collection (name, created and text)?

Again, thanks for helping me out, learned already a lot from your answer!

  1. It depends on what you want to achieve and what data structure do you have.
    If you need to iterate through several posts that belong to some groupId, than you can name it posts (groupId) {}, if you want to output only one post (always), then post (groupId) {}.

  2. It depends on how complicated is comments part. If you want to follow trends and simplify migration to React, then use separate template and put down data to it from parent template. If you just want to use blaze in a small/medium project than you can use “complexity” rule. When template become complex or you can use parts of it in different places, then refactor it to separate small “dumb” templates and one parent template. Or just put some things out.

  3. No, don’t put ‘use strict’ here.

  4. Yes, totally ok.

1 Like

Imho creating separate template for what’s inside of your {{#each}} loop is almost always the better decision. Especially when you deal with separate collections.

1 Like

How is it with modal boxes that are shown? Would they be in a separate template as well? What are the pros and cons, @brajt?

I have put the comments section into a separate template but it’s 119 lines of html, that’s still very hard to read. It has a sidebar, a main, a footer section and a modal.

What would be best practice to increase readability and maybe even avoid some common error?

My modals consist of following templates:

  • main container for the modal, called f.e. loginModal, which manages the state of the modal
  • the layout modal, being a block template called modalWrapper. It gives the modal a proper structure and I may or may not pass some arguments to it, f.e. in order to increase the padding, depending on what I use the modal for. Of course, I put the modal’s content wrapped in this block template. Internally it’s build of additional subtemplates that are listed below:
  • header template for the modal, called modalHeaderSnippet. By default it grabs the name of the parent container template to know which modal it’s a part of and then looks the headers list to get the text it displays as the modal’s headline (f.e. “Sign in”) and in the shadow or subheadline (f.e. “Sign in to your account”). But I may pass the text as an argument instead, if I want it to be dynamic. I may also pass the name of the styling f.e. to change the color of the header part.
  • footer template which is one of the two - modalFooterWrapper or modalFooterSnippet, depending on if the particular modal has any actions. If it has, I use block template modalFooterWrapper which…
  • which contains even more subtemplates. Each button of the footer template is made by calling buttonSnippet to which I pass arguments such as the text, the action it should call (as I use manuel:viewmodel package and I prefer to manage the actions this way instead of the event map), the name of the icon it should have (if any), the name of the styling (f.e. “primary”) and eventually, if the button is meant to submit a form, a for=“inputName”, in which case the button becomes a button-looking label that calls the submit action in an input name inside of the form which exists in the modal.

As you can notice, I call my reusable templates Snippets (for casual templates) and Wrappers (for block templates).

2 Likes

@brajt would you mind posting an example of the above. This sounds quite complicated and I lost you somewhere along your lines. You can PM with the code as well if you don’t want to post it publically. Thanks in advance and it sounds like a well thought out idea (just that I don’t fully understand it yet)

I’ll post it here when I’m back home.

As promised, here’s the selection of few templates that I use for modals.

template(name='registerModal')
  +modalWrapper
    +modalHeaderSnippet
    +modalContentWrapper
      +formWrapper(id='registerForm')
        +fieldUsername(ref='username')
        +fieldEmail(ref='email')
        +fieldPassword(ref='password')
        +checkboxSnippet(
          id='checkbox'
          text="I solemny swear that I'm up to no good")
    +modalFooterWrapper
      +buttonSnippet(
        text='sign in'
        bind='click:login'
        link='login')
      +buttonSnippet(
        class='primary' 
        text='sign up'
        icon='user'
        submit=true)

template(name='modalWrapper')
  .ui.modal.small
    +Template.contentBlock

template(name='modalContentWrapper')
.grid-text($b="class:class")
  .grid-content
    .ui.attached.basic.segment.content
      +Template.contentBlock

template(name='modalHeaderSnippet')
  .grid-header($b="class:class")
    .grid-content
      .ui.top.attached.segment
        .shadow($b="if:shadow") #{shadow}
        .shadow($b="unless:shadow")#{header}
        | #{header}
  .header-border

template(name='modalFooterWrapper')
  .footer-border
  .grid-footer
    .grid-content
      .ui.bottom.attached.segment
        +Template.contentBlock

Advantages of such approach:

  1. You can focus on the content of your modal (or other template) instead of dealing with styling
  2. As your templates aren’t don’t depend on HTML but on subtemplates, you can do whatever you want with your HTML - you can easily switch CSS framework or styling or anything and it won’t break your app
  3. You only have to change one small template in order to affect all modals at your app
  4. You can automate many things - see how there’s totally no mention of the header text in my modal templates, as the text is loaded automatically by subtemplate, based on the data from main template (or you can pass it down if you prefer)
  5. Each template manages separate data context, so you don’t need to wonder what should work and what shouldn’t in {{#with}} or {{#each}}
  6. I will be easier to make a transition to React later

Notice that I do the very same thing for forms (in the first template).

2 Likes