Display only users with a specific role in meteor-tabular table

My site allows users to apply by connecting their google account, as soon as an account is created they’re given a “pending” role (using alanning:roles package). I would like to have a table for admins to see when new applicants have applied, from there the admin can properly manage the users application (change role to accepted, declined, etc.). So, I have created my table, but it’s showing all users, I’m wondering if someone knows a way to make it so only users with the “pending” role are shown in my table?

Here is what I have so far:

TabularTables.ManageApplications = new Tabular.Table({
name: ‘ManageApplications’,
collection: Meteor.users,
allow: function (userId) {
return Roles.userIsInRole(userId, ‘admin’);
},
autoWidth: false,
oLanguage: {
“sSearch”: "Search: "
},
columns: [
{ data: //column details here },
{ data: //column details here },
{ data: //column details here },
{ data: //column details here },
{ data: //column details here },
],
});

This works, but it shows every user (not just users with the “pending” role).

I then created this to try and publish only data for pending users:

Meteor.publish(“pendingUsers”, function() {
var isAdmin = Roles.userIsInRole(this.userId, ‘admin’);
if (isAdmin) {
return Roles.getUsersInRole(‘pending’).fetch();
} else {
return null;
}
});

and subscribed by adding pub: "pendingUsers", to my table. This somewhat works, it makes it so it only shows data in the columns for “pending” role users, but, it still lists every user and just has blank spaces where the data would be.

If anyone knows how I can achieve this it would be greatly appreciated if you could give some insight as I’ve been stuck on this for quite a while… I believe it may have to do with “Displaying Only Part of a Collection’s Data Set” in the Tabular readme, but I’m very unsure of how to set this up. Any examples or help is extremely appreciated.

I’ve made some changes and added a selector, here is where I’m at now.

The table:

TabularTables.ManageApplications = new Tabular.Table({
name: 'ManageApplications',
collection: Meteor.users,
pub: "pendingUsers",
selector: function( userId ) {
  return Roles.getUsersInRole('pending');
},
allow: function (userId) {
  return Roles.userIsInRole(userId, 'admin');
},
autoWidth: false,
oLanguage: {
"sSearch": "Search: "
},
columns: [
{ data: //column details here },
{ data: //column details here },
{ data: //column details here },
{ data: //column details here },
{ data: //column details here },
],
});

The publication:

Meteor.publish("pendingUsers", function() {
 var isAdmin = Roles.userIsInRole(this.userId, 'admin');
   if (isAdmin) {
     return Roles.getUsersInRole('pending');
   } else {
     return null;
   }
});

With this setup though (when adding the selector part) I receive the following error in my server console, and the table itself appears empty and says “No data available in table”:

I20160404-14:20:29.064(-7)? Exception from sub tabular_getInfo id fJiDJkTpYaEtHsjNw { stack: ‘TypeError: Converting circular structure to JSON\n at Object.stringify (native)\n at Object.stringify (/Users/username/.meteor/packages/ecmascript-runtime/.0.2.6.1hlo1r4++os+web.browser+web.cordova/npm/node_modules/meteor-ecmascript-runtime/node_modules/core-js/modules/es6.symbol.js:127:21)\n at [object Object].cursorProto.(anonymous function) (packages/meteorhacks_kadira/packages/meteorhacks_kadira.js:2965:1)\n at [object Object].kadira_Cursor_map [as map] (packages/meteorhacks_kadira/packages/meteorhacks_kadira.js:3362:1)\n at [object Object].Package (packages/aldeed_tabular/server/tabular.js:110:1)\n at packages/matb33_collection-hooks/collection-hooks.js:275:1\n at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)\n at [object Object].handler (packages/matb33_collection-hooks/collection-hooks.js:274:1)\n at maybeAuditArgumentChecks (livedata_server.js:1698:12)\n at [object Object]..extend._runHandler (livedata_server.js:1023:17)’,
I20160404-14:20:29.064(-7)? source: ‘subscription’ }

Been stuck on this for a few days now so if anyone by any chance has any ideas on how I can get this working it would be greatly appreciated, thanks!

I read more and see there are some requirements when creating a custom publish function I’m guessing this is whats causing the error. I see in the [Meteor Roles 2.0] (github.com/alanning/meteor-roles/tree/v2.0) api docs that I can set [queryOptions], I believe this is what I need to do I’m just a little unsure of how this would look.

This seems like it should be extremely easy but everything I’ve been trying has been failing… If anyone has any ideas it would be greatly appreciated!

You shouldn’t really need a custom publish function, it’s mainly the selector option that you’ll want to use to filter out the users you want. You’ll also want to make sure that the users Role data is something you’ve subscribed to though.

The thing about the Tabular custom publication is, as I understand it, that you can use it to filter field data that is returned from each record, but not which records are returned. So that’s what the selector is for.

I’ve always used the selector in the actual template call:

{{> tabular table=TabularTables.ManageApplications selector=selector class="table table-striped table-bordered table-condensed"}}

And then:

Template.yourTemplate.helpers({
  selector: function () {
    return {
      roles: 'pending'
    };
  }
});

You shouldn’t need the selector in your table declaration. Let me know if this helps!

1 Like

Oh ok, this does make sense because if I remove my custom publish function as well as my selector then I see all the users in my table as well as their roles (I’ve already published roles) and other necessary info. But then if I add my selector to my table definition as shown above, it just leaves my table empty saying “No data available in table” and has the “Processing…” popup kinda frozen there…

  selector: function(userId) {
    return Roles.getUsersInRole('pending');
  },

Any ideas of where I might be going wrong with this?

Thanks for the reply!

I’ve given this a try, unfortunately it doesn’t seem to be working for me though. It seems when I add this I just get an empty table and the “No data available in table” message. I’ve removed it and can verify when I do so I see all the users/roles listed in the table so I’m not sure where exactly it’s going wrong…

When you can see all the data, and you do a

Meteor.users.find({
  roles: 'pending'
}).count()

in the console, do you get the expected count?

Nope that seems to only return “0” even when I can see all the users and their roles listed in my table. But when I run Roles.getUsersInRole(‘pending’).count() in my browser console it returns the accurate amount of users in that role.

Where are you storing the role data in your users collection?

The selector function needs to return a Mongo query, not a cursor. So maybe something more like this:

selector: function(userId) {
    return {
        _id: {$in: Roles.getUsersInRole('pending')
                        .map(function(user){ return user._id} ) }
    }
},

(Note: untested)

3 Likes

Bingo! This seemed to solve the problem and seems to be working perfectly. :slight_smile:

Thank you @heschong and @vigorwebsolutions both very much for the help, been stuck on this for a while!

Props to @heschong for getting it solved!

1 Like

If you want to check all the rules of such a group:

     selector: function (userId) {
       {return 'roles.myrole': { '$ exists': true}};
     },

Or with just a few:

     selector: function (userId) {
       {return 'roles.myrole': {$ in: [ 'admin', 'viewer', 'editor']}};
     },