简体   繁体   中英

calling a template helper function from inside a template event callback

I am very new to meteor and it is possible that I am going about this entirely incorrectly.

I have a simple template that represents a menu bar. When the user clicks an Icon, the menu is supposed to appear. When they click it again, it is supposed to disappear.

Here is the markup:

<template name="menu">
  <div class="menu">
    <div class="toggler">
      <i class="fa fa-bars fa-3x"></i>
    </div>
    <div class="menu-body">
       <!-- ... -->
    </div>
  </div>
</template>

Here is the JS that I have:

Template.menu.helpers({
    self: Template.instance(),
    menu_body: self.find('.menu-body'),
    toggler: self.find('.toggler'),

    currently_open: false,
    open: function() {
        menu_body.style.display = 'flex';
    },
    close: function() {
        menu_body.style.display = 'none';
    },
    toggle: function() {
        if(currently_open) close();
        else open();
    }
});

Template.menu.events({
    'click .toggler': function(event, template) {
        console.log(template);
        template.toggle();
    }
});

I thought the template instance would have access to the helper functions, but according to the log statement, this is what the template instance consists of:

B…e.TemplateInstance {view: B…e.View, data: null, firstNode: div.menu, lastNode: div.menu, _allSubsReadyDep: T…r.Dependency…}
  _allSubsReady: false
  _allSubsReadyDep: Tracker.Dependency
  _subscriptionHandles: Object
  data: null
  firstNode: div.menu
  lastNode: div.menu
  view: Blaze.View
  __proto__: Blaze.TemplateInstance

Can someone point me in the right direction here. Please feel free to be scrutinous if I am going about it wrong.

Helpers are for functional calls - not event driven works.

Meteor has an events handle that you can use to track events like clicks. Also you can use your css classes to define the styles nicely without programatically overwriting them.

Template.name.events({
'click .menuToggler': function(event, template) {
  event.preventDefault();
  var menu = template.find('.menu-body'); //(make this in ID!)
  if($(menu).hasClass('menuOpen')) {
     $(menu).removeClass('menuOpen');
     //menu.style.display = 'none';
  } else {
     $(menu).addClass('menuOpen');
     //menu.style.display = 'flex'; Use css to define these on the menuOpen class
  }
});

Some things to note: This event handle assumes that your menu-body class is available under the template called "name" in my example. So you will want this event handler at the most top level template you have. It also assumes.

If you want to share state between the various components of your template (helpers, event callbacks etc) it should be done by setting properties directly on the template instances.

This can be done through the onCreated() callback

As per the documentation:

Callbacks added with this method [are] called before your template's logic is evaluated for the first time. Inside a callback, this is the new template instance object. Properties you set on this object will be visible from the callbacks added with onRendered and onDestroyed methods and from event handlers.

These callbacks fire once and are the first group of callbacks to fire. Handling the created event is a useful way to set up values on template instance that are read from template helpers using Template.instance().

So, to provide a more relevant and concise example than the one in my original question.

Template.menu.onCreated(function() {
  this.items =  [
    {title: 'Home',    icon: 'home'},
    {title: 'Profile', icon: 'user'},
    {title: 'Work',    icon: 'line-chart'},
    {title: 'Contact', icon: 'phone'}
  ];
});

Template.menu.helpers({
  items: function() {
    var self = Template.instance();
    return self.items;
  }
});

Template.menu.events({
  'click .toggler': function(event, template) {
    console.log(template.items); //[Object,Object,Object,Object]
    //do something with items
  }
});

That's actually funny but I created a mini package that helps you do just that: https://atmospherejs.com/voidale/helpers-everywhere

But in your case it's not the right way of doing it. I can you see you want to add an display either flex or none it's better add CSS element like active that hold display: flex and add active or remove it on click like this: $('').addClass('active') or $().removeClass('active')

one liner can also work here: $('.menu-body').toggleClass('active')

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