hharnisc / meteor-accounts-admin-ui-bootstrap-3

A roles based account management system using bootstrap 3 for Meteor
MIT License
56 stars 55 forks source link

Adding custom columns to the users table #9

Open Waiski opened 10 years ago

Waiski commented 10 years ago

I'd like an option for adding custom columns to the users table, like there is in the non-bootstrap3 -version. Is there any special reason why this feature does not exist?

If there are no objections on adding this feature, I could try to implement it myself (although I'm a newbie, but this task doesn't seem very complicated)

hharnisc commented 10 years ago

It just hasn't been implemented yet. I think custom fields are an important feature.

The problem with the other implementation is that the templates containing the extra fields are not included in the package (otherwise the parent template doesn't load). So in keeping it simple I pushed that feature out.

If you've got a solution that would work with or without the extra fields template tags I'd be very interested in pulling it into the package.

Waiski commented 10 years ago

After looking for some guidance in SO, I got a solution for this. However before I make any pull requests, I think it should be considered if custom templates are the way to go on this, or would it be more convenient if the custom fields would be added by using some configuration options.

Something like:

AccountsAdminUI.configure({
    customFields: [
        {
            label: "Phone Number",
            attributeName: "profile.phoneNo",
            editable: true
        },
        {
            label: "Google ID",
            attributeName: "services.google.id",
            editable: false
        }
    ]
});

That way of specifying the user's attribute wouldn't be good, but you get the point.

Which way do you prefer? The configurator may seem a bit cumbersome to some, but then again creating the header, cell and edit fields in separate templates isn't very DRY.

hharnisc commented 10 years ago

I like the configuration method because its explicit and simple :+1:

Waiski commented 10 years ago

I started writing something in that direction, but now I can't decide on the specifics about how the cell content should be specified. Ideally, I think, users could specify the custom cell content in at least these three ways:

1. Simply an attribute of the user object:

field: "profile.phoneNo"

2. As a function that takes the user object and returns a string:

field: function(user) {
  if (user.profile.phoneNo.length > 7)
    return user.profile.phoneNo;
}

3. As a template, that automatically gets user as its data context:

field: "phoneNumberField"
<template name="phoneNumberField">
  <span class="glyphicon glyphicon-earphone"></span>
  {{profile.phoneNo}}
</template>

Now the things to consider here:

Waiski commented 10 years ago

Please review what I came up with. This does not yet do anything to the info or edit boxes, so options editable and inInfo don't do anything yet.

As an example, I have a collection of organizations, and I store one organizationId per user. The configuration can be used to show each user's organization's name like this:

Configuration:

AccountsAdminUI.config({
    columns: [
        {
            label: "Organization",
            attribute: "organizationId",
            template: "userOrganizationCell",
            editable: false
        }
    ]
});

Template:

<template name="userOrganizationCell">
    {{organizationName}}
</template>

Helper:

Template.userOrganizationCell.helpers({
    organizationName: function() {
        if (this.user.organizationId)
            return Organizations.findOne(this.user.organizationId).name;
        return "";
    }
});

This works nicely and reactively. The biggest problem is that I have to check if the organization ID is set in the helper function although all users should have it set. This is because the template compilation is run somehow "eagerly" before all data is loaded, and it loops once with incomplete user data (only the current user's basic info). This could probably be avoided either using waitOn in the router or perhamps some other (better) way. I'll look into it.