[Solved] How to display collection count in template

Hi, I am trying to create a way to display the number of documents in a collection (ProductoCarrito) I made this method on server:

Meteor.methods({
  numeroDeProductos: function () {
        return ProductoCarrito.find().count();
    }
});

Then in the client js I added

Template.categorias.helpers({
  numeroDeProductos: function() {
    return Meteor.call("numeroDeProductos");
  }
});

And to dsplay it on the “categorias” template I tried using:

{{numeroDeProductos}}

but nothing happens, can anybody here help me, or tell me another way to get this done? Thanks in advance!

2 Likes
Template.yourTemplate.helpers({
  productCount: function() {
    return Products.find().count()
  }
});

Then in the template with the name yourTemplate

{{productCount}}
4 Likes

Thanks for the super quick response!

The only reason why what @corvid suggested might not be what you’re after is - in the example you originally posted, you are checking to see how many documents the server has.

With the suggestion above, you are checking to see how many documents the client has. (you may not be subscribing/published all the documents for whatever reason)

If you want to use the Meteor.call you won’t be able to reactively update the field. You need to have a call back that sets a session variable, or a reactivevar. The helper needs to just relay that variable into your template.

1 Like

@cosio55 you should check https://github.com/percolatestudio/publish-counts

1 Like

Your original problem is that Methods run asynchronously on the client. So return Meteor.call('numeroDeProductos') will always be undefined.

What you need to do is to provide a callback function like so

Template.categorias.helpers({
  numeroDeProductos: function() {
    Meteor.call("numeroDeProductos", function(err, res){
     if(!err) Session.set("numeroDeProductos", res);
    });
    return Session.get("numeroDeProductos");
  }
});

3 Likes

that is what I was going for with my reply but was too lazy to write up an updated helper function. :smile:

I believe the best solution to this problem is the solution outlined by MDG in the documentation.

// server: publish the current size of a collection
Meteor.publish("counts-by-room", function (roomId) {
  var self = this;
  check(roomId, String);
  var count = 0;
  var initializing = true;

  // observeChanges only returns after the initial `added` callbacks
  // have run. Until then, we don't want to send a lot of
  // `self.changed()` messages - hence tracking the
  // `initializing` state.
  var handle = Messages.find({roomId: roomId}).observeChanges({
    added: function (id) {
      count++;
      if (!initializing)
        self.changed("counts", roomId, {count: count});
    },
    removed: function (id) {
      count--;
      self.changed("counts", roomId, {count: count});
    }
    // don't care about changed
  });

  // Instead, we'll send one `self.added()` message right after
  // observeChanges has returned, and mark the subscription as
  // ready.
  initializing = false;
  self.added("counts", roomId, {count: count});
  self.ready();

  // Stop observing the cursor when client unsubs.
  // Stopping a subscription automatically takes
  // care of sending the client any removed messages.
  self.onStop(function () {
    handle.stop();
  });
});

// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");

// client: subscribe to the count for the current room
Tracker.autorun(function () {
  Meteor.subscribe("counts-by-room", Session.get("roomId"));
});

// client: use the new collection
console.log("Current room has " +
            Counts.findOne(Session.get("roomId")).count +
            " messages.");

// server: sometimes publish a query, sometimes publish nothing
Meteor.publish("secretData", function () {
  if (this.userId === 'superuser') {
    return SecretData.find();
  } else {
    // Declare that no data is being published. If you leave this line
    // out, Meteor will never consider the subscription ready because
    // it thinks you're using the added/changed/removed interface where
    // you have to explicitly call this.ready().
    return [];
  }
});

This way you will keep the count reactive without publishing the entire collection to the client. I also like this method because it doesn’t require you to install any additional packages to your project.

4 Likes

I think the snippet @jamgold provided is just as reactive and also doesn’t publish the whole collection to the client.

It will not be reactive. The meteor call will only run once because the helper function will only get called once on page render. The session variable is reactive and it will give you the correct output exactly once per page load. If the count changes the helper will not re-run.

Sorry you’re 100% right!!!

if the Session were to be updated elsewhere, then the helper would run again. However since the helper runs once, and only calls the method once that means the Session only updates once. It will not reactively update with changes on the server… :weary: I was wrong!

2 Likes

Corvid, this solution is fine when you don’t use limit to paginate the results.
Since is good to use pagination to display information the recomendation is to use the cosio55’s soluction