Monday, 11 March 2013

Infopath List Form – hide/disable fields based on SharePoint group membership

As we know in SharePoint 2010 we can customize list form using Infopath 2010. With Infopath 2010 we will get some advantages of more flexible look and feel, data validation/rules as well as web services invocation in the form of data connection without writing any single of code as in fact Infopath list form does not support code behind.
In this post I will show how to use Infopath data connection to build rules for hiding/disabling fields based on the SharePoint group membership of current user. In my case I would like to disable the Approval field as shown below for any users that are not member of  a SharePoint group called Form Administrator.
Here is my steps to achieve the goal:
  1. The first very step obviously is clicking the Customize Form on the ribbon to edit the form in Infopath Designer. I wouldn’t go to any detail of how to build a list form using Infopath 2010 as there are already a lot of posts about the topic for example this msdn article.
  2. Adding 2 received from SOAP Web Services data connections to the forms, again there are a lot of articles about this topic, so I wouldn’t go into any detail such as this one.
    • GetUserProfileByName in http://<server-name>/_vti_bin/UserProfileService.asmx. Tick Automatically retrieve data when the form opened.
    • GetGroupCollectionFromUser in http://server-name/_vti_bin/UserGroup.asmx (put a sample value, of an existing account such as contoso\account_name). Untick automatically retrieve data when the form opened.
  3. Save the form as source files as we are going to modify the xml schema of the GetGroupCollectionFromUser data connection. The reason why we need to do this is that the generated data connection doesn’t display the returned fields. As shown in the picture  that the dataFields  children elements only contain userLoginName which is not correct.
    To save the form as sources go to Files -> Publish as shown below then  click Export Source Files on the next window. The exported files would look like in the picture. It consists of infopath definition file (manifest.xsf), xml schemas of all data connections (.xsd files), some xml files that contain sample data of the data connections and an xsl file (view.xsl) used for form rendering. In our case we only focus on GetGroupCollectionFormUser.xsd (the xml schema for GetGroupCollectionFromUser data connection).
  4. Modify the GetGroupCollectionFromUser1.xsd, make sure close the Infopath Designer before editing. I found this approach from Sumit’s SharePoint blog, he explained how to correct the xsd in the ‘Correcting the xsd for the Return Fields’ section in his post. To summarize his approach basically, we need to add this below type definition
    01<s:complexType name="GetGroupCollectionFromUserType">
    02    <s:sequence>
    03      <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string"/>
    04      <s:element minOccurs="0" maxOccurs="1" name="Groups">
    05        <s:complexType>
    06          <s:sequence>
    07            <s:element maxOccurs="unbounded" name="Group" >
    08              <s:complexType>
    09                <s:attribute name="ID" type="s:unsignedShort"></s:attribute>
    10                <s:attribute name="Name" type="s:string"></s:attribute>
    11                <s:attribute name="Description" type="s:string"></s:attribute>
    12                <s:attribute name="OwnerID" type="s:unsignedByte"></s:attribute>
    13                <s:attribute name="OwnerIsUser" type="s:string"></s:attribute>
    14              </s:complexType>
    15            </s:element>
    16          </s:sequence>
    17        </s:complexType>
    18      </s:element>
    19    </s:sequence>
    20  </s:complexType>
    below this line (at the 2nd line of the file)
    1<s:import namespace=""></s:import>
    Then find this below
    1<s:element name="GetGroupCollectionFromUser">
    2   <s:complexType>
    3     <s:sequence>
    4     <s:element minOccurs="0" maxOccurs="1" name="userLoginName" type="s:string">
    5         </s:element>
    6   </s:sequence>
    7    </s:complexType>
    8  </s:element>
    Replace it with this:
    1<s:element name="GetGroupCollectionFromUser" type="tns:GetGroupCollectionFromUserType">
  5. Create a rule to invoke GetGroupCollectionFromUser web services method. As the method is not invoked when the form is opened, we need to invoke the method after the GetUserProfileByName invocation finished. To do this, right click on the manifest.xsf and choose Design. Choose GetUserProfileByName data connection and apply rules on the PropertyData field as display in the picture.
    The rule condition is Name=”AccountName”, rule type is Action. The rule actions are:
    1. Set field’s value: the userLoginName of the GetGroupCollectionFromUser’s queryFields to the Property value AccountName from the GetUserProfileByName.  how to set the property value (please follow steps 7 – 10)
    2. Query for data: GetGroupCollectionFromUser. (no need screen shot for this :) )
  6. Create a formatting rule for the field (in my case approval field) that we want to disable/hide if current user is not member of a SharePoint Group. Put a condition as below, where The Form Administrator is the SharePoint Group Name.
    And the any occurrence & number of occurrence of Name is the SharePoint groups’ name retrieved from the dataFields of GetGroupCollectionFromUser data connection below, in other words the rule check if any of the groups’ name is Form Administrator or no SharePoint groups found associated with the current user, if condition met, disable the field.
  7. And finally publish the form
Please feel free to give me feedback if there is better approach.

No comments:

Post a Comment