meteorspacebars

#each helper to populate a table


I'm fairly new to meteor and I'm trying to iterate over a cursor using #each to populate a table. Here's my code:

<template name="choral">
<div class="container" style="padding-top: 25px">
  <div class="table-responsive">
    <form id="orderForm">
    <table class="table table-borderless table-dark">
      <thead class="thead-light">
        <tr>
            <th>Title:</th>
            <th>See the Music:</th>
            <th>Hear the Music:</th>
            <th>Format:</th>
            <th>Price (per copy):</th>
            <th>Quantity:</th>
        </tr>
      </thead>
      <tbody>
         {{#each piece in pieces}}
        <tr>
            <td id="name">{{piece.name}}</td>
            <td id="pdf">PDF</td>
            <td id="audio">AUDIO</td>
            <td id="format">FORMAT</td>
            <td id="price">{{piece.score}}</td>
            <td id="qty"><input type ="number" name ="quantity" min="5"></td>
        </tr>
        {{/each}}
      </tbody>
      <tfoot>
            <tr>
                <td colspan="5"></td>
                <td><button class="button" type ="submit">Add to Cart</button></td>
            </tr>
        </tfoot>
  </table>
  </form>
  </div>
</div>  

my js.

Template.choral.helpers({
  pieces: function(){
    return choralm.find({});
  }
});

I'm outputting a blank row between the #each tag. I publish the collection server side and subscribe. I'm just not sure where to look. Any ideas? My publishment and subscription:

Meteor.publish('choralList', function() {
  return choralm.find();
});

Template.choral.onCreated( function(){
  Meteor.subscribe('choralList');
});

Solution

  • As far as I can see you are subscribing to your data but you are not "telling" your template, that the subscription is finished and it should redraw.

    Therefore your template immediately renders while the subscription is ongoing and thus uses the yet empty collection data.

    In order to inform your template that data has been updated you can use it's internal Tracker and store the information in a reactive data-source (for my example I use ReactiveDict instead of ReactiveVar).

    import { ReactiveDict } from 'meteor/reactive-dict';
    
    Template.choral.onCreated( function (){
      // inside onCreated, this refers to the
      // current template instance 
      const instance = this;
    
      // let's attach a ReactiveDict to the instance
      instance.state = new ReactiveDict();
    
      // use the internal Tracker
      instance.autorun(() => {
        // subscribe and store a flag, once ready
        const choralListSub = Meteor.subscribe('choralList');
        if (choralListSub.ready()) {
          instance.state.set('subscriptionComplete', true);
        }
      });
    });
    

    Next you add a helper, that returns the reactive value for 'subscriptionComplete':

    Template.choral.helpers({
      pieces(){
        return choralm.find({});
      },
      subscriptionComplete() {
        // we use 'state', our ReactiveDict,
        // which we added as prop in onCreated
        return Template.instance().state.get('subscriptionComplete');
      }
    });
    

    And finally we let our template draw the data, once our subscription is complete. Until the subscription is complete (note the {{else}} block), we display a message about the loading status:

    <template name="choral">
    <div class="container" style="padding-top: 25px">
      {{#if subscriptionComplete}}
      <div class="table-responsive">
        <form id="orderForm">
        <table class="table table-borderless table-dark">
          <thead class="thead-light">
            <tr>
                <th>Title:</th>
                <th>See the Music:</th>
                <th>Hear the Music:</th>
                <th>Format:</th>
                <th>Price (per copy):</th>
                <th>Quantity:</th>
            </tr>
          </thead>
          <tbody>
             {{#each piece in pieces}}
            <tr>
                <td id="name">{{piece.name}}</td>
                <td id="pdf">PDF</td>
                <td id="audio">AUDIO</td>
                <td id="format">FORMAT</td>
                <td id="price">{{piece.score}}</td>
                <td id="qty"><input type ="number" name ="quantity" min="5"></td>
            </tr>
            {{/each}}
          </tbody>
          <tfoot>
                <tr>
                    <td colspan="5"></td>
                    <td><button class="button" type ="submit">Add to Cart</button></td>
                </tr>
            </tfoot>
      </table>
      </form>
      </div>
      {{else}}
      <div>Loading template...</div>
      {{/if}}
    </div>
    </template>
    

    Related resources

    TemplateInstance.autorun

    http://blazejs.org/api/templates.html#Blaze-TemplateInstance-autorun

    https://docs.meteor.com/api/tracker.html

    Reactive stores

    https://guide.meteor.com/data-loading.html#stores

    Subscription readyness

    https://guide.meteor.com/data-loading.html#readiness

    Helpers

    http://blazejs.org/guide/spacebars.html#Built-in-Block-Helpers