I was working with a client recently in a simplified signup site.  One overall important requirement was to keep the interface as simple and easy as possible for the users, eliminating any possibility for the users to make mistakes.  For this sign up functionality, all the functionality was kept to one list.  Users would browse a list of available sessions to choose from, edit the session item, and fill in an attendee field with their name.  For this, when the user would edit the session item, we wanted to only allow them to edit the attendee field, and not anything about the session (title, date/time, location, etc.).  In effect what was needed was to make the fields read only based on the role of the user. 

As with most things in SharePoint, you could accomplish this many different ways:

  • SharePoint Designer and custom list forms
  • Customize the list forms with InfoPath
  • JavaScript

For simplicity, I went the first route, just using SharePoint Designer and a custom list form.  To demonstrate the final result, this is the edit form when an admin user with Designer-level permissions edit an item:

image

All of the fields are editable.  When a non-admin user with Contribute-level permissions goes to sign up (where there is no attendee in the item), they get a mostly read-only view except for the attendee field:

image

If a non-admin user edits an item where they are in the attendee field, they still get the edit control but only for the Attendee field (in essence we only allow them to edit the field if its their item):

image

If a non-admin user edits the item where they are NOT in the attendee field, they do not get the edit control:

image


To accomplish this, we will perform the following basic steps:

  • Open the site in SharePoint Designer
  • Create a custom edit list form
  • Apply conditional formatting on the existing fields for Design-level users using IfHasRights formula expression
  • Make new read-only fields that will only show for Contribute-level users using IfHasRights formula expression
  • Hide the cancel button
  • Create a custom permission level so users can’t create or delete any items, but only edit them

Let’s get started. 

Create the Custom List Form

  1. Go to the site where you want to implement this functionality.  I am assuming you already have a list for this purpose, but in case you don’t, for my example create a new calendar.  Create a list column called Attendee that is a person field.  Click Site Actions –> Edit in SharePoint Designer.
  2. Click on your list.  Under Forms, click New, and choose Edit form, give it a name and click Ok.  Right click on your new form (Editform3.aspx in my case), and click Edit file in advanced mode.
  3. We need to hide the edit fields except for Design-level users.  For each field you want to restrict, left-click on the field in the design view, then right-click and choose Select –> row.  Then from the Web part / Options ribbon tab, click Conditional Formatting –> Show content


    image 

    Then on the Condition Criteria dialog, click on the Advanced button.  Change the category to Boolean, and double-click on IfHasRights.  Here we type the ID of the granular permission we want to use (number).  You can find the list of numbers in the file CAML2XSL.XSL at C:\Program Files (x86)\Microsoft Office\Office14, or here is a simple table.  For my case, I want users to have the ManageList permission, so enter 2048.  Click Ok and ok


    image

  4. Repeat step 3 for all fields you want admins to be able to edit.  In my case, I wanted to do this for all fields except the Attendee field as we need to be more restrictive with this field. 
  5. As with the other fields we want Admins to be able to edit this field, but we only want the contribute users to edit this field if either it is empty (no one has signed up) or if their name is in the field so they can cancel their signup.  Highlight the Attendee field row as before, and go into the Conditional formatting options.  For the expression, paste the following:  contains(substring-before(substring-after(string(@ParticipantsPicker),'">'),'</a>'), $UserID) or @ParticipantsPicker = '' or ddwrt:IfHasRights(2048)
    1. The reason we have to do all that substring stuff is because of the format of the people picker box.  It has a lot of HTML in it.  You can see this in the data source details, or in the advanced expression preview if you just add your people picker to the expression.  What we’re doing is basically selecting the text between these characters:  

      ">C5 Contractor</a> 

      So we’re saying get me all text after the “>, and all text before the </a>, leaving just the username that will compare to the UserID properly.
         
    2. I will say that the contains part of the formula was finicky.  At one point it wouldn’t work, and I just re-pasted the full XSL tag <xsl:if test="contains(substring-before(substring-after(string(@ParticipantsPicker),'&quot;&gt;'),'&lt;/a&gt;'), $UserID) or @ParticipantsPicker = '' or ddwrt:IfHasRights(2048)"> and that worked. 
    3. Also, if after you paste it and click Ok once, you should see it say “Using advanced expression”.  If it doesn’t and just says “add a new clause”, the formula didn’t stick.  I found I had to add a simple clause with the Attendee field = Current User, click Ok, delete it from the XSLT, then I could paste the full line above and it would stick.
  6. Right click where you want to have your read only fields, and click to Insert –> Row.  Do this for the same number of fields you want to display read only.  For example, if you have 3 fields above that are the full edit fields, then you need 3 rows to hold the read-only equivalent as well.
  7. For each column, be sure on the right side of SharePoint Designer, In Data Source, you have Data Source Details shown so you can see the list of fields.  For each field, click where the value goes, and just drag the column from the Data Source Details and drop it on the form.  The text based value should appear.  Basically instead of actually rendering the form field, we are saying just display the text value of the field using the structure <xsl:value-of select=”@Title” />.  You should get something like this:

    image


    Welcome to the world of custom list forms.  In custom list forms, you have to fix a few things (notice the date and the people picker field?). 
  8. To fix the dates, we need to tweak the xsl select statement.  Change it from:
    1. <xsl:value-of select="@EventDate" />       TO
    2. <xsl:value-of select="ddwrt:FormatDate(string(@EventDate), 1033, 5)" />

      Thanks to this blog for the fix on this.
  9. To fix the Attendee field, right click on the value string, and click Format Item –> Text. 

    image

    Things should be looking better:

    image

  10. Now we need to apply the conditional formatting for these read only fields.  For all fields except Attendee, do the same procedure as above, but instead of a Show Content format, use Hide Content.  Use the same expression ddwrt:IfHasRights(2048).  We’re saying that admins should NOT see these fields, because they are going to be able to see the full form fields.  These fields are targeted to the lower-privilege users.  As you apply each format, the field will disappear from the form (as it should).
  11. For the read-only Attendee field, use the same formula as on the show expression for the same field: contains(substring-before(substring-after(string(@ParticipantsPicker),'&quot;&gt;'),'&lt;/a&gt;'), $UserID) or @ParticipantsPicker = '' or ddwrt:IfHasRights(2048)
    1. We’re basically hiding the field if the same is true.  Hide this field if it is not blank, or if this is an admin, or if the current user is not the same person. 
  12. We also wanted to hide the Cancel  button because we were finding that a lot of users were clicking Cancel thinking they were cancelling their session (when they should be removing their name from Attendee and click Save).  It's very simple to do this.  Click on the Cancel button, and inside the tag, add visible="false".  To do this, in the code view change this <SharePoint:GoBackButton runat="server" ControlMode="Edit" id="gobackbutton2"/> to this <SharePoint:GoBackButton runat="server" ControlMode="Edit" id="gobackbutton2" visible="false" />.  Be sure to do this for both buttons.  A great side benefit to this is that it will automatically also grays out the Cancel button in the ribbon.
  13. Now all we need to do is make this field the default form.  Save your changes, then go back to the List properties in SharePoint Designer.  Highlight your form, then on the ribbon click Set as default.

    image

On a side note, for the Attendee field I am doing checking on the people picker for that field.  But you could also use the Created By field (@Author) or Modified By (@Editor) instead of @ParticipantsPicker in the expressions above.

NOTE:  If things don’t work, go inspect the XSLT in code view for the formula VERY CAREFULLY.  I saw a few times where pieces of the expression where removed or changed, and I had to just paste in the full XSL.  I will provide here for easy pasting (be sure you are closing the xsl tag with </xsl:if>):

  • SHOW Expression for Attendee
    • <xsl:if test="contains(substring-before(substring-after(string(@ParticipantsPicker),'&quot;&gt;'),'&lt;/a&gt;'), $UserID) or @ParticipantsPicker = '' or ddwrt:IfHasRights(2048)">
  • HIDE Expression for Attendee
    • <xsl:if test="not(contains(substring-before(substring-after(string(@ParticipantsPicker),'&quot;&gt;'),'&lt;/a&gt;'), $UserID) or @ParticipantsPicker = '' or ddwrt:IfHasRights(2048))">

image

Create Custom Permission Level

Whew!  Ok now we just need to create the custom permission level.  Again this is to ensure that non-admin users can only edit existing items, and cannot add or delete items. 

  1. Go to the root of the site collection, click Site Actions –> Site Permissions, then click Permission levels
  2. Click on Contribute.  Scroll to the bottom of the page, and click the button Copy permission level.
  3. Give it a name like Edit items only, add a description that explains more detail, and under List Permissions, uncheck the following, then scroll to the bottom and click Create:
    1. Add items
    2. Delete items

      image

  4. Go back to your site, and assign permissions either on the root or the list (whatever makes sense for your environment).  In my case, I will use the default site Members group. 

    image

Test it out, you’re done!  This should work with SharePoint Foundation or Server, and doesn’t require any coding or InfoPath.  Hope you learned something!


For more information about C5 Insight or this blog entry, please Contact Us