Replacing helpers with viewmodel


#1

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}}

#2

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}}

#3

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.


#4

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.


#5

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.