Monday, June 24, 2013

Hide Columns in a SharePoint list based on SharePoint group

It seems to be a fairly common request to hide particular columns on a SharePoint form based on the SharePoint group that a user is a member of. One solution to this problem would be to create custom forms for Add, Edit, and Display in SharePoint using SharePoint designer. Then figure out a way to hide and show the columns. This requires SharePoint Designer access and may not always be an option. It also requires the user to read through ASP.NET / XSL markup and figure out how to do it. This is a very tedious task and hardly easy to maintain. The good news is that this is a truly secure solution since the data is not sent to the client (browser). If you have these strict security requirements then you may want to go this route. FYI, I have read that InfoPath is also an option, but I don't like going that route either.

I am working on an internal instance of SharePoint 2010 and simply hiding the data on the forms using CSS is sufficient because the user would have to look in the source of the page to see the data.

WARNING:
Note: This is NOT a true security solution! All data (even for hidden columns) is sent to the browser, but is just hidden from user's view in the browser.

In my case, it would not be the end of the world if users viewed source to see all the data. We are all part of the same company after all. If this is your scenario, then you may want to consider the solution outlined below.

My solution uses a JavaScript library called SPUtility.js. It makes hide and showing a field simple. It also makes changing a field to readonly simple as well. I can't take credit for the library, but I am very happy I found it. The only problem left to solve was how to get the current user and the groups that the user is in. This is something I had to come up with. It requires CSOM (Client Side Object Model) which requires SharePoint 2010 or later. I read that you can use SPServices if you are using MOSS 2007, but I have not tried to do it.

To implement the functionality to get user and group information, I wrote the following methods.

You can download the source here.

function getCurrentUserObject(callbackFunc)

function isCurrentUserInSharePointGroup(sharePointGroupID, callbackFunc)

function isUserInSharePointGroup(userLogin, sharePointGroupID, callbackFunc)

CSOM uses asynchronous calls for everything which makes it difficult to code if you are not accustomed to it. The good news is all you have to do is provide the callback function to make use of these functions. While that may sound difficult, just follow the example I have provided. In the example code the first thing it does is make sure the CSOM library (sp.js) is loaded and then executes our code. It takes the approach of getting the current user then seeing if the user is in the owner group and setting column visibility appropriately. If the user is not in the owner group it then looks in the members group and sets the column visibility appropriately. If they are not in either of those groups it sets the column visibility appropriately. You could continue on with different checks if desired.

Here is a snippet of what the solution code looks like:

function doOwnerChanges(userLogin, isInGroup)
{
  if (isInGroup)
  {
 
   SPUtility.GetSPField('Title').Show();
   SPUtility.GetSPField('Cost').Show();
   SPUtility.GetSPField('Customer Comment').Show();
   SPUtility.GetSPField('Assigned To').Show();
   SPUtility.GetSPField('Internal Comments').Show();
  }
  else // not in owner group let's see if they are in members group
  {
 
   isUserInSharePointGroup(userLogin, 7, Function.createDelegate(this, this.doMemberChanges));
 
  }
}


As you can see it is easy to maintain because all the complexity is abstracted away. If another column is added you would just add a line to the above code.



Added solution to your page

  1. Download the following:
    • SPUserGroupUtility.js My code that gets the current user and checks the groups the user is in.
    • ShowHideColumnExample.js (only needed if you want an example of how to use this solution). You can replace or not use this in your specific implementation. This is the file you will need to specify your columns. The name is not important except that you reference it later.
    • SPUtility.js This provides the functionality for hide/showing fields and making them readonly, etc.
    • Prototype.js Required by SPUtility.js.
    • sp.js - actually you don't need to download it. Ultimately, this is the CSOM library. It is provided by SharePoint 2010. Just use it in your code as needed.
  2. Upload the .js file to somewhere on SharePoint where all users can access the files. I recommend installing your .js file in your Site Assets directory on your site. You can find it by going to Site Action | View All Site Content | Site Assets.
  3. Navigate to form (EditForm.aspx or NewForm.aspx)
    In SharePoint 2010, you can choose Form Web Parts -> Default whatever Form
  4. Add a Content Editor Web Part to the page
  5. Edit the web part
    In SharePoint 2010, click the arrow -> Edit Web Part.
  6. Edit the content editor's HTML to add some JavaScript
    In SharePoint 2010, under Editing Tools -> Format Text click the HTML button -> Edit HTML Source
  7. Follow the instructions on installing the SPUtility.js
  8. <script src="/sites/someSite/SiteAssets/prototype.js" type="text/javascript"></script>
    <script src="/sites/someSite/SiteAssets/SPUtility.js" type="text/javascript"></script>
    <script src="/sites/someSite/SiteAssets/ShowHideColumnExample.js" type="text/javascript"></script>
    <script src="/sites/Brent/SiteAssets/SPUserGroupUtility.js" type="text/javascript"></script>
  9. Save the page / stop editing.

Troubleshooting

  • NOTE: To just try SPUtility.js you can try the install instructions.
  • If nothing happens on the page, make sure you don't have any errors. You may need to do an F12 in IE to see the error console. Also, you can look at the F121 | Network tab to see if the JavaScript files are able to be found.
  • You can always start the JavaScript debugger and see where it is breaking.

No comments: