aslagle / reactive-table

A reactive table designed for Meteor
https://atmospherejs.com/aslagle/reactive-table
Other
328 stars 138 forks source link

How to pass subscription arguments to reactive table publish collection #195

Open sparupat opened 9 years ago

sparupat commented 9 years ago

Hi,

I have a use case where collection subscription parameters change based on user input. I tried to pass client subscription arguments to reactive table function using below syntax but it did not work for me. Can you please let me know the suggested workflow to pass arguments to publish functions?

ReactiveTable.publish('paginate_user_stats', Stats, function(year,count) { return Stats.find({season: year, count: count}, {sort: {season: -1}), {"enableRegex": false});

Thanks, Sri

aslagle commented 9 years ago

ReactiveTable.publish doesn't handle that, but you can tie your user inputs to custom ReactiveTable filters on those fields - see https://github.com/aslagle/reactive-table#custom-filters.

SachaG commented 9 years ago

Any news on this? My use case is displaying a table of users, and then each user having a "purchases" column where I want to display a nested reactive table. I would like to limit that reactive table's publication to the user's _id (basically a client-side join).

It seems like this isn't currently possible?

aslagle commented 9 years ago

I think you could do it with custom filters - a unique filter for each table containing the user's _id, with all the tables using the same publication. They don't need to be set by user inputs. They're not that easy to set up right now though. I'm thinking about changing it so you can pass in queries on the client without creating a ReactiveTable.Filter.

SachaG commented 9 years ago

But then that would still require publishing the entirety of the Purchases collection, right? Unless I'm missing something?

It would definitely be great to be able to do:

collection: "admin-user-purchases",
publication-options: {...}

(or something similar)

Also, I would suggest maybe adding a publication option when subscribing to a server-side publication instead of overloading the collection option?

aslagle commented 9 years ago

When you call ReactiveTable.publish, it calls Meteor.publish with a bunch of arguments including the filters. You do have to publish the entire collection, but you can subscribe to one user id at a time. It would be difficult to combine publication options with the publication arguments needed by the package.

SachaG commented 9 years ago

(see updated below)

SachaG commented 9 years ago

OK, I've fixed a couple mistakes with the code I posted previously. Here's my template code (adminUsersPurchases is called by the parent table):

<template name="adminUsersPurchases">
  {{> reactiveTable settings=settings}}
</template>
Template.adminUsersPurchases.onCreated(function () {
  var user = this.data;
  this.filter = new ReactiveTable.Filter("userPurchasesFilter_"+user._id, "userId");
  this.filter.set(user._id);
});

Template.adminUsersPurchases.helpers({
  settings: function() {
    var user = this;
    return {
      collection: "admin-user-purchases",
      filters: ["userPurchasesFilter_"+user._id]
    };
  }
});

And my publication code:

ReactiveTable.publish("admin-user-purchases", function (userId) {
  if(Users.isAdminById(this.userId)){
    return Purchases;
  } else {
    return [];
  }
}, function () {
  var userId = this._params[1][0]; // hacky way to get filter parameter
  return {userId: userId};  
});

It seems like it should be working, but nothing is showing up in the table. The fact that Reactive-Table bypasses the usual Minimongo collections makes it hard to know if I'm successfully publishing the data or not.

aslagle commented 9 years ago

Hmm, I think the fields argument to ReactiveTable.Filter might need to be an array. Sorry if that's the problem, I should make it accept a string or at least give an error message. You don't actually need the second function in ReactiveTable.publish, since ReactiveTable is already adding the filter to the query, but I think it would still work as long as you got the parameter correctly.

I wanted to have the first function return a cursor like Meteor.publish, but I would've had to do something really hacky to add the sorting and pagination stuff to it after it was created.

SachaG commented 9 years ago

Awesome, it works! In case others are wondering, here's the final code:

Client:

Template.adminUsersPurchases.onCreated(function () {
  var user = this.data;
  this.filter = new ReactiveTable.Filter("userPurchasesFilter_"+user._id, ["userId"]);
  this.filter.set(user._id);
});

Template.adminUsersPurchases.helpers({
  settings: function() {
    var user = this;
    return {
      collection: "admin-user-purchases",
      filters: ["userPurchasesFilter_"+user._id]
    };
  }
});

Server:

ReactiveTable.publish("admin-user-purchases", function () {
  if(Users.isAdminById(this.userId)){
    return Purchases;
  } else {
    return [];
  }
});

I can submit a PR to add that use case to the documentation, if you think that'd be useful?

aslagle commented 9 years ago

Sure, that would be great.

SachaG commented 9 years ago

Done :)

funston commented 9 years ago

is there some docs for this now? would be helpful. trying to get something working here. i never see the server publish any data.....

SachaG commented 9 years ago

Yeah, I added a section to the docs. Note that Reactive-Table has its own publication thing, you won't see the data appear in your regular collections.