javascriptmeteormeteor-blazespacebars

pass current value of spacebars:this as argument to new helper in meteor/blaze


I am finding unique instances of years in a Mongo collection and passing them to my template as list items. Underneath these i want sub lists with the unique occurrences of months in that given year, but I can't figure out how to pass the year to my month() helper so that I can limit the query.

The HTML is...

        <template name="list">
          <ul>
            {{#each year}}
                <li>
                    <h2>{{this}}</h2>
                </li>
                <ul>
                    {{#each month}}
                        <li>
                            <h3>{{this}}</h3>
                        </li>
                    {{/each}}
                </ul>
              {{/each}}
          </ul>
        </template>

And the JS is...

  let monthNames = ["January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
  ];

  let findYears = function(){
    var distinctYears = _.uniq(Events.find({}, {
      sort: {start: 1}, fields: {start: true}
    }).fetch().map(function(x) {
      var d = new Date(x.start);
      return d.getFullYear();
    }), true);
    return distinctYears;
  };

  let findMonths = function(){
    var distinctMonths = _.uniq(Events.find({}, {
      sort: {start: 1}, fields: {start: true}
    }).fetch().map(function(x) {
      var d = new Date(x.start);
        return monthNames[d.getMonth()];    
    }), true);
    return distinctMonths;
  };

  Template.list.onCreated( () => {
    let template = Template.instance();
    template.subscribe( 'events' );
  });

  Template.list.helpers({
    year() {
      foundYears = findYears();
      return foundYears;
    },
    month() {
      foundMonthNames = findMonths();
      return foundMonthNames;
    }
  });

I would like to be able to pass the year which my year() helper is currently on as an argument to my month() helper so that I can edit my findMonths function to limit it's query to only events which fall in that year but I have no idea how to do this nor how to query MongoDB from the client for only a month (all my events dates are in ISODate format).

I hope my issue is clear. I apologize, I know that I'm probably using improper terminology.


Solution

  • If I understand correctly, you have two issues - passing the year into your month helper, and using that parameter to make your query more specific - is that right?

    To pass the year into the helper, change your code following the {{#each thing in things}} convention (explained here). So your template code would become:

    <template name="list">
      <ul>
        {{#each year in getYears}}
          <li>
            <h2>{{year}}</h2>
          </li>
           <ul>
             {{#each month in (getMonths year)}}
               <li>
                 <h3>{{month}}</h3>
               </li>
             {{/each}}
           </ul>
         {{/each}}
       </ul>
     </template>
    

    And then your year helper would stay the same (except I've changed the name to make it clearer!), and your month helper would just accept the argument:

    Template.list.helpers({
        getYears() {
          foundYears = findYears();
          return foundYears;
        },
        getMonths(year) {
          foundMonthNames = findMonths(year);
          return foundMonthNames;
        }
      });
    

    Finally, your findMonths function. There may be an different/easier way, but you could get the year by comparing earlier and later dates (i.e. greater than December 31st of the previous year and less than January 1st of the next year:

    let findMonths = function(year){
        var query = {
          start: {
            $gt: new Date(year - 1, 11, 31),
            $lt: new Date(year + 1, 0, 1)
          }
        }
        var distinctMonths = _.uniq(Events.find(query, {
          sort: {start: 1}, fields: {start: true}
        }).fetch().map(function(x) {
          var d = new Date(x.start);
            return monthNames[d.getMonth()];    
        }), true);
        return distinctMonths;
      };
    

    (you can add hours, minutes, and ms if you like to get it to just before midnight)