meteor-tabular icon indicating copy to clipboard operation
meteor-tabular copied to clipboard

Set columns by role

Open felipesmendes opened this issue 9 years ago • 19 comments

How can I set to Tabular.Table that I want to show more 2 colunms if I have administrator role?

felipesmendes avatar Mar 10 '16 15:03 felipesmendes

I've already gone through... 5? Maybe more issues asking this same thing. And I'm still looking for a way to do it.

I've tried to use the visible option dinamically (this is, using a function to get that true/false value), but it seems to be called only when the meteor app starts, not when it's rendered so, no userId value at all.

Any ideas or just an straight statement that this can't be done?

luixal avatar Jun 15 '16 10:06 luixal

I had same idea like you but din't work...something like this:


columns: [{
data: "name",
title: "Name",
className: "center aligned",
orderable: true,
visible:function(){
//If user set to see this columns returns true else return false
}
}, {
data: "ultimaPosicao.id",
title: "ID",
className: "center aligned",
orderable: false,
visible:function(){
//If user set to see this columns returns true else return false
}
}];

felipesmendes avatar Jun 15 '16 11:06 felipesmendes

I was doing the same but using a global función like this:

isAdmin = function() {
  // returns true if user has admin roles (using alanning:roles)
}

so I would hace something like this un the tabular definition:

  ....
  visible: isAdmin(),
  ...

No luck. A console.log in the isAdmin function shows up only on app startup, not when table is rendered :(

The only working solution I've found is having two different tabular table definitions (which sucks and is what I wanted to avoid) and according to user role, show one or another in the template using template helpers. As the columns I'm hidding are the same in all tables, I'm generating the second tabular definitions dinamically at startup time, but that's not the solution I'm looking for.

luixal avatar Jun 15 '16 11:06 luixal

@aldeed Could you help us with this solution?

felipesmendes avatar Jun 15 '16 12:06 felipesmendes

As also mentioned from me in the issue https://github.com/aldeed/meteor-tabular/issues/295 i would suggest you to make a server method which creates the tabular table on the server side and after that init the tabular table on the client side. important for this is, that the tabular on the client side is created AFTER the initalization on the server side.

I already us this kind of function. It would be nice if in future this would be automaticly made from the package. So that I could place the code of the tabular only the client-side and not in common code

kevinpeter avatar Jun 17 '16 14:06 kevinpeter

@kevinpeter Please, Do you have any example code of this sugestion?

felipesmendes avatar Jun 17 '16 14:06 felipesmendes

Here is a code example (I removed some code, which is used for personal. I hope it still works ;) ):

Server-Side

Meteor.methods({
    defineTabularTable:function(name, collectionName, columns, extraFields, selector, publishName){
        //Check if tabular already exists on server side
        if(!_.isUndefined(TabularTables[name])) return;

        var tableProperties = {
          name: name,
          collection: db[collectionName],
          columns: columns
        };

        if(!_.isUndefined(publishName))  tableProperties.pub = publishName;
        if(!_.isUndefined(publishName))  tableProperties.extraFields = extraFields;
        if(!_.isObject(selector))        selector = {};



        tableProperties.selector =  function( userId ) {
                                        //Here you can make global role and right checks
                                        //if(!hasRights(userId)) return;

                                        return selector;
                                    };

        TabularTables[name] = new Tabular.Table(tableProperties);
    }
});

Client-Side Template

<template name="tabularTable">
    {{initRenderStart}}
    {{#if isReady}}
        {{> tabular table=_tableData class="table  table-condensed"}}
    {{else}}
        {{initPublish}}
        <div >
            <div class="col-sm-5"></div>
            <div class="col-sm-1">
                Loading ...
            </div>
            <div class="col-sm-5"></div>
        </div>
    {{/if}}
</template>

Client-Side JS

Template.tabularTable.helpers({
    isReady:function(){
        if(_.isUndefined(this._isReady)) this._isReady = new ReactiveVar(false);
        return this._isReady.get();
    },
    initRenderStart:function(){
        this._isReady = new ReactiveVar(false)
    },
    initPublish:function(){
        Template.tabularTable.init(this, false);
    },
    _tableData: function() {
        return Template.tabularTable.init(this, true); 
    },
});


Template.tabularTable.init = function(data, isPublishReady) {
        var self = data;
        var tabularConf = {
                                             collection:self.collection,
                                             selector:self.selector,
                                             extraFields:self.extraFields,
                                             columns:self.columns
                                      }



        var name = tabularConf.name + "_" + tabularConf.collection._collection.name + JSON.stringify(tabularConf.selector);


        if(isDefined(TabularTables[name])) {
            if(isUndefined(self._isReady)) self._isReady = new ReactiveVar(false);
            self._isReady.set(true);
            return TabularTables[name];  
        }




        if(!isPublishReady) {
            Meteor.call('defineTabularTable', 
                name, 
                tabularConf.collection._collection.name,
                tabularConf.columns,
                tabularConf.extraFields,
                tabularConf.selector,
                tabularConf.pub,
                function(error) {
                    if(error) {
                        console.log(error);
                    }
                    else
                    {
                        self._isReady.set(true);    
                    }
                }
            );    
        }
        else
        {
            var tabularOptions = {
                name        : name,
                extraFields : tableOptions.extraFields,
                selector    : function( userId ) {
                                return tabularConf.selector;
                              },
                collection  : tabularConf.collection,
                columns     : tabularConf.columns,
                responsive: true,
                autoWidth: false,
                throttleRefresh: 5000
            };

            if (!_.isUndefined(self.tabularConf.pub)) tabularOptions.pub = tabularConf.pub;

            if(!_.isUndefined(name)) {
                TabularTables[name] = new Tabular.Table(tabularOptions);
                return TabularTables[name];
            }
            else
            {
                return new Tabular.Table(tabularOptions);  
            }
        }    
}

And you should now call the template like following:

<template name="test">
{{> tabularTable name="myTabularTableTest"
     collection=collection
     selector=selector
     extraFields=extraFields
     columns=columns
}}
</template>

And if you want to show a column depending on the user role, you could modify the Server-Method defineTabularTable and the Client-Function Template.tabularTable.initto show or hide a column.

kevinpeter avatar Jun 17 '16 15:06 kevinpeter

Sounds great @kevinpeter , I'll give it a try. Thanks! :)

luixal avatar Jun 17 '16 15:06 luixal

@kevinpeter how did you defined db variable?

Exception while invoking method 'defineTabularTable' ReferenceError: db is not defined

felipesmendes avatar Jun 20 '16 14:06 felipesmendes

Its an object. where each collection is saved. For examle:

db = {};
db.tasks = new Mongo.Collection('tasks');

I will try to make a repo with a demo on the comming weekend for helping you.

kevinpeter avatar Jun 20 '16 15:06 kevinpeter

@kevinpeter It will be awesome! Waiting for this repo! Thank you so much!

felipesmendes avatar Jun 20 '16 18:06 felipesmendes

@kevinpeter In my case I do not use object to store collection instante...just use global variable like this:

Tasks = new Mongo.Collection('tasks');

felipesmendes avatar Jun 20 '16 18:06 felipesmendes

@kevinpeter You could make the repository with example for us?

felipesmendes avatar Jun 26 '16 23:06 felipesmendes

@luixal You could get something through the example? Could you share with me?

felipesmendes avatar Jun 28 '16 18:06 felipesmendes

I will publish the example tomorrow evening. Until now, I did not found time to implement the examples.

kevinpeter avatar Jun 28 '16 18:06 kevinpeter

@kevinpeter thank you so much!

felipesmendes avatar Jun 28 '16 18:06 felipesmendes

Hi @felipesmendes , I finally went with something like this on the initComplete tabular field:

initComplete: function (settings, json) {
    // calls a function for hidding columns according to indexes AFTER table has been init on client:
    hideTableColumns(this, [0, 9, 10, 11]);
  },

this is the implementation for the hideTableColumns function:

// hides columns for indexes on the provided tabular table:
hideTableColumns = function(table, columnsToHide) {
  // this line is here only for admin users to see all columns:
  if (Meteor.user() && Roles.userIsInRole(Meteor.user()._id, 'admin')) return;
  // here goes the hidding:
  var dt = table.DataTable();
  columnsToHide.map(function(columnIndex) {
    dt.column(columnIndex).visible(false);
  });
};

Not the best solution, but works pretty well :)

luixal avatar Jul 06 '16 12:07 luixal

Awesome man! I'll try!

I, you and @kevinpeter can improve the project documentation or implement the best way to do this in the package and create a pull request.

What do you think?

Other structure problem that I have is all tabular table definition is in one file in the root folder of project and I want to separate then in many files for any report that I have.

How do you do that?

felipesmendes avatar Jul 06 '16 13:07 felipesmendes

@felipesmendes sorry man, didn't read this until now (same on me) :(

As Tabular is a really big project, I don't fell confident enough to get into the code because probably, someone else knows the project better to implemente something like this.

Also, I'm having trouble with responsiveness (DataTables problem in fact) so maybe I have to move on to another solution for displaying collection.

luixal avatar Oct 10 '16 17:10 luixal