Replacing helpers with viewmodel

I’m trying to replace my helpers with a view model component, but I can’t get the same functionality. The issue with the helpers is that I need to use a reactive variable to get the results of a callback function, but that seems to create a looping function call when the data is mostly static. It seems to make my application go really really slow and I tried to implement the same functionality with view model, but it doesn’t work.

It’s currently using the following:

Template.discussDashboard.helpers({
    discussion: function(){
      var instance = Template.instance();
      Meteor.call('user.subscriptions', function(error, result){
        if (error) console.log("Error");
        instance.discussions.set(result);
      });

      areas = instance.discussions.get();
      return {area : areas};

      }
});

And the following:

 {{#with discussion}}
 {{#each area}}

    <tr>
    <td>
      <a style="color: black; font-size: 20px" href="/discussions?area={{this}}">
      <span>&nbsp;&nbsp;<b>#{{this}}</b></span>
      </a>
    </td>
    </tr>

 {{/each}}
 {{/with}}

I’m tried to change it to the following, but nothing displays.

Template.discussDashboard.viewmodel({
  discussions: [],
  addDiscussions: function() {
    var self = this;
    Meteor.call('user.subscriptions', function(error, result) {
      if (error) console.log("Error");
      self.discussions(result);
    });
  }
});

With the following:

{{#each discussions}}

  <tr>
  <td>
     <a style="color: black; font-size: 20px" href="/discussions?area={{b "text: this"}}">
     <span {{b "text: this"}}></span>
     </a>
  </td>
  </tr>

{{/each}}

Here’s how you do it without changing too much of your app (I’m not a fan of the whole “Meteor calls for everything” approach):

First install simple:reactive-method. Then use the following:

Template.discussDashboard.viewmodel({
  discussions: function() {
    return ReactiveMethod.call("user.subscriptions");
  }
});
{{#each discussions}}
  <tr>
  <td>
     <a style="color: black; font-size: 20px" href="/discussions?area={{this}}">
     <span>{{this}}</span>
     </a>
  </td>
  </tr>
{{/each}}

Thanks again! I appreciate it.

As far as I understand, Meteor calls are the only way of getting stuff done on the server without using collections on the client. If you have a suggestion as to how to approach the issue, then I would like to hear it.

I think you should stick with what “clicks” for you. Seems like you’re happy with Meteor calls.

In practice there’s little difference between ReactiveMethod.call("user.subscriptions") and UserSubscriptions.find(), so I go with the simplest. I can always create collection methods or a “data access layer” if I don’t want to use the collections directly from the view models.

btw, one approach that works well is to use mixins the same way Angular uses services. For example you could have the following:

ViewModel.mixin({
  userData: {
    all() {
      return Users.find();
    },
    admins() {
      return Users.find({ isAdmin: true });
    }
    // etc.
  }
})
Template.example.viewmodel({
  mixin: {
    userData: 'userData'
  }
})

<template>
  {{#each userData.all}}
    Show user data
  {{/each}}
</template>

That way you segment the data access into separate buckets which can be used by different view models. You could have more buckets for each collection.