Clayton's SharePoint Madness

All About SharePoint, InfoPath, and SharePoint Designer!

Posts Tagged ‘browser’

Auto-Numbering InfoPath Forms

Posted by Clayton Cobb on June 15, 2009

How do I avoid getting NaN when using the max() function? There is already a blog post referencing this, but people seem to be having trouble with it, so I am going to explain the steps in detail with screenshots.  Here are the steps that SYM Wong-A-Ton gave:

  • Change the RetrieveIDs data connection to use the autonumber field instead of max(@ID) + 1.
  • Add a Button to the form with the following 4 rules:
    • Query the RetrieveIDs data connection
    • Set the autonumber field equal to 1 when count(@ID) = 0
    • Set the autonumber field equal to max(@ID) + 1 when count(@ID) > 0
    • Submit the form to the form library
  • Disable the submitting of the form via the Submit button on the toolbar (the Button you added will submit the form instead)

These steps make sense, but you have to know how to actually configure your button settings to match the words.  I think some more steps are needed, so here is my outline:

  1. Create RetrieveIDs data connection
  2. Create hidden fields for storing the ID and Filename
  3. Create a Submit data connection for your that uses Filename field for submit filename
  4. Disable toolbar options
  5. Create custom button with 5 rules

Create RetrieveIDs data connection Create a RECEIVE data connection in your form template that connects to the Form Library where the form resides.  Unless you want other metadata from this library, only select the ID field when configuring the DC.  On the last page, make sure to deselect the checkbox for “Automatically retrieve data when form is opened.”  We want to retrieve the data at the exact moment before submitting the form just in case someone else has submitted a form while our form was open (Fig 1).

Fig 1 – Data connection to retrieve IDs from the SharePoint List 

Create hidden fields for storing the ID and Filename Create a numID field (Whole Number) and strFilename field (Text).  Do not set any conditional formatting, rules, or data validation on these.  Add them to the canvas for now and make them read-only (Fig 2).  These will be visible for testing purposes only.

Fig 2 – Create hidden fields for ID and Filename

Create a Submit data connection that uses the strFilename field for dynamically creating the filename Create a SUBMIT data connection in your form template that connects to the Form Library where the form resides.  Put in the URL of your Form Library for the “Document Library” field, and choose the strFilename data element for “File name” field by using the fx button.  Check the box for “Allow overwrite if file exists” (Fig 3).

Fig 3 – Creating the Submit data connection for the Form Library

Disable toolbar options Click Tools > Form Options > Browser.  Uncheck Save, and Save As (Fig 4).  Submit should be grayed since it has not been configured.  If it has been configured, be sure it is unchecked.  Update should be unchecked by default, so leave it.  I personally uncheck “Views,” since I use views to dynamically route people to certain information based off their identity or the form’s workflow status, but it’s up to you.  If your form is not browser-enabled, use the Open and Save menu in Form Options to uncheck Save and Save As.

Fig 4 – Disabling toolbar functions for Browser-Enabled Forms

Create custom button with 5 rules

Fig 5 – The full view of the 5 Rules

  • 1) Query the RetrieveIDs data connection (Fig 6)

Fig 6 – Querying the RetrieveIDs data connection

  • 2) Set numID to the the next incremental ID only with two conditions – there is at least one form already existing in the library and only if the current form has not already been submitted (Fig 7)
    • Set a condition rule to have two conditions
      • For the first, click “Select a field or group,” select the RetrieveIDsdata source from the top pulldown, drill down to the IDdata element, and choose “Number of occurrences of ID” in the bottom pulldown.  Select the operand “is greater than” and type the number 0 in the last box. 
      • For the second condition, simply choose strFilename in the first pulldown and set the operand to “is blank.”

Fig 7 – Setting the incremental ID with conditions

  • Create one action that sets numID to the next number higher than the highest ID in the form library (Fig 8).  For the Action, choose “Set a field’s value.”  For the Field, choose numID.  For Value, click the fx button and put in the formula max(@ID) + 1(do not copy and paste this – you must use the Insert Function and Insert Field buttons to make sure it resolves properly.  You can also copy this Xpath string: xdMath:Max(xdXDocument:GetDOM(“RetrieveIDs”)/dfs:myFields/dfs:dataFields/dfs:AutoNumbering/@ID) + 1

Fig 8 – Setting the ID to the next incremental value

What we are accomplishing here is that we are giving our current form the next ID in line before submitting the form.  We are making sure this rule only runs when the library is not empty, because it would cause an error when there is no ID to use for the max(ID) function.  Also, we are only setting this value when the form is brand new, which means it has no strFilename yet.  We have to do this so that if the form is edited, there will be no change to the numID field.  We only want this rule to run when the library is not empty and when the form is brand new.

  • 3) Set numID to 1 upon the single condition that the form library is empty (Fig 9).
    • Set a condition rule to have one condition.  Click “Select a field or group,” select the RetrieveIDsdata source from the top pulldown, drill down to the IDdata element, and choose “Number of occurrences of ID” in the bottom pulldown.  Select the operand “is equal to” and type the number 0 in the last box.

Fig 9 – Setting the Initial ID with a condition

    • Create one action that sets numID to 1 (Fig 10)

Fig 10 – Setting the ID to 1 for the first form in the library

What we are accomplishing here is that we are giving our form the first ID of “1” due to the fact that it is the first form to be submitted to the library.  This is only possible when the form is brand new, so there is no need to add a condition related to the strFilename.  All we need to do is check to see if the form library is empty.  This step circumvents the NaN error when using max(ID) and getting a null value back.  Also, notice that this rule is put in line AFTER the Set Next ID step above.  The reason for this is because both rules would run if they were in the opposite order, and you’d be skipping IDs.

  • 4) Edit the existing form without changing numID or strFilename, then close it (Fig 11).
    • Set a condition rule to have one condition stating that strFilename is not blank.
    • Add two actions in this order:
      • Submit to your SharePoint Library Submit data connection
      • Close

Fig 11 – Editing the form with the submit data connection

Here, we are simply submitting the form back to the library in a manner that will not change any metadata and will overwrite the existing file of the same name.  This is the whole reason for the strFilename field.  We do not want the strFilename to be recreated each time the form is edited.  This rule is placed before the Submit rule for the same reason as stated above.  We need to check first to see if the form has already been submitted.  If so, then we submit using the current strFilename.  If not, then we skip this rule.

  • 5) Submit the current form only if it is brand new and after dynamically creating the strFilename, then close it.
    • Set a condition rule to have one condition stating that strFilename is blank.
    • Add three actions in this order:
      • Set the Value of strFilename (Fig 12) to the concatenated string combining userName() with the numID field.  The formula is concat(userName(), numID).  The Xpath is concat(xdUser:get-UserName(), my:numID).
      • Submit to your SharePoint Library Submit data connection
      • Close

Fig 12 – Setting the dynamic filename prior to submission

Here, we are submitting the form to the form library for the first time.  This is why we first dynamically create the strFilename, because the Submit data connection uses this field to create the filename in SharePoint.  We only want to do this step upon first submission, so that is why this rule only runs if the strFilename is blank.  Doing this rule last keeps us from double-submitting, because the Edit rule would run right after the Submit rule due to its condition being met (strFilename is not blank).  You can of course choose any concatenation formula you want, or you can use no formula and simply use the numID value – this part is up to you. After publishing the form template, go to your library, which should be empty with no files ever having been submitted (Fig 13), otherwise the ID of the actual files in the library won’t start with 1, and the InfoPath numID won’t match the SharePoint ID.

Fig 13 – In your new Form Library with no history of records, click New

The new, blank form should look like this (Fig 14):

Fig 14 – Blank version of the form

Click Submit, and you should be returned to the library showing just one file (Fig 15), and it should have the Name of username1 (i.e. ccobb1).

Fig 15 – First list item is correctly given the ID of 1

Click on that file to re-open it, and it should show the populated fields with numID = 1 and strFilename = ccobb1 (Fig 16).

Fig 16 – Form data fields show proper ID and Filename after submission

Click Submit again, and notice that you go back to the form library, but nothing has changed on the form except the Modified date/time stamp.  The ID did not increment, and a new file was not created, because we were just editing the same file.  Now, click New again, and submit.  You should see a new file with a Name that is equivalent to ccobb2.  Do this several times and edit some of those forms several times to ensure they all behave properly. There is one big problem with all of this, though, and I’ll demonstrate it for you.  This entire concept works well UNLESS all the forms get deleted so that there are no forms remaining.  If you do that, then the next form you create will be given the numID of 1 and the strFilename of ccobb1.  However, in SharePoint, the ID will be the next highest ID in succession after the highest ID that had been created and subsequently deleted.  Deleting files in a SharePoint list does not re-start the ID increment, so keep that in mind.  If you delete all but one of your forms, then the numID solution we have here continues to work.  Here is an pic showing what happens if you delete all but one of the forms and then create a new one (Fig 17).

Fig 17 – AutoNumbering continues even after records have been deleted as long as there is at least one record in the library

Three other major concerns are the scalability issue, the View settings issue, and the heavy use issue.

  • Scalability – The data connection is pulling down the ID of every form in the main view of your form library.  What if you have hundreds or thousands of forms?  You will be pulling down tons of info that will slow the form load when all you need is a single piece of info – the highest ID in the list.  A potential workaround for this is to create a custom view that is set to Sort by Created in Descending Order with a finite Item Limit of 1 (Fig 18).  This always show only ONE item, and that will be the item with the highest ID in the entire list, because IDs are assigned upon creation of the file, so the most recently created file will have the highest ID.  The problem then becomes that you need to create a data connection directly to this view instead of the library itself (DCs to SP lists use the default view).  To do this, you must create an XML data connection pointing to the XML view of that SP view by using this write-up: Populating Form Data from SharePoint List Views.  Believe me, this works, and I use it all the time, but I can imagine if it seems daunting to people who are just trying to figure out the entire solution above.  To be clear, this DC would replace your RetrieveIDs DC from step 1.

Fig 18 – View Settings for showing only the list item with the highest ID#

  • View Settings – Similar to the above issue, the Max(ID) function is only going to return the highest ID that InfoPath sees in the default view.  The default view settings for a form library are to limit the items to 100.  Also, any filtering on the default view would potentially cause InfoPath not to see every ID.  You either have to make sure your default view has EVERY list item visible with no Item limit, or you need to use the above alternative view that shows only the highest ID form.
  • Heavy Use – By heavy use, I mean that new forms are being created very frequently – enough that there is the potential for multiple people to submit new forms within the same moments (the window of time depends on the speed of the system), because this method relies on being able to read the items in the library to get the current Max(ID).  If both get submitted close enough together, there is a chance that they assign themselves the same ID or that the submit fails altogether.  It’s best to submit the doc, retrieve the ID after submission, then submit again (all in one button push), but this only works if you don’t need the ID itself in the filename.

Posted in InfoPath 2007, MOSS 2007 | Tagged: , , , , , , | 134 Comments »

User Roles in Browser-Enabled InfoPath Forms Using Contacts List

Posted by Clayton Cobb on June 14, 2009

MAJOR REVISION that uses the GetCommonMemberships web method to determine group memberships for users without needing to use contact lists or any other manual data source!

InfoPath – User Roles in Browser-Enabled Forms Using Groups

So, you need to restrict certain controls in your InfoPath form, but it’s browser-enabled, and you just found out that User Roles are not supported, huh?  You also see that SharePoint permissions do not help restrict specific areas within your form, so what do you do?  There are probably several methods, but here is the one I have come up with that uses all built-in functions of InfoPath and MOSS 2007 without any code.

Here is an outline of the steps with the assumption that you already have a working, browser-enabled form:

  1. Contacts List
  2. Add GetUserProfileByName data connection to your form template if not already using it
  3. Add necessary fields to form template and configure them
  4. Add conditional formatting to applicable controls

Contacts List

In this solution, the Contacts list will provide the groupings of users for your “roles” within the form..  Here are the steps:

  • Create a new Contacts List
  • Click Actions > Connect to Outlook (this step only for Office 2007/IE 6-8 users) – Fig 1
  • Populate users from Global Address Book (or manually) – Fig 2 and 3
  • Add any extra columns for sub-grouping of users (i.e. Department) 

Fig 1 – Connecting to Outlook

Fig 2 – Add Contact from Global Address Book in Outlook

Fig 3 – Copy local Contacts to Synchronized SharePoint Contact List

 Fig 4 – Final View of Contacts List Synchronized with Outlook

What we have done is used Outlook 2007’s two-way  integration with SharePoint to ensure that our contact information in the SP Contacts List is exactly the same as what is in Active Directory, and since our profile import in this scenario is pulling from Active Directory, then our user information should all be synchronized.  Notice that I’ve added a Department column to the Contacts list, because this info is in AD, the GAL, and in the SP profile database. Note: other data has been removed but would usually be seen here (email address, phone #, etc).

User Profile Service – GetUserProfileByName method

Now we must add this superb web service to our form template as a data connection.  Please use the first 8 steps of Itay’s writeup to get this done as I can only give him credit for my extensive knowledge of this web service.  Once you’ve added it successfully, we need to do a few things with it using the later steps in Itay’s blog.

Add Necessary Fields to Form Template and Configure Them

First, create two basic text fields in your main data source: strCurrentUserEmail and strCurrentUserDepartment.  Next, drag two section controls to your canvas, and drag both text fields from above (Fig 5).

 Fig 5 – Sample Form Template

Next, we need to get those fields populated with the proper information for only the current user, which means each subsequent user who opens the form will make the data in these fields change accordingly.

strCurrentUserEmail – Tools > Form Options > Open and Save > Rules.  Add an action that sets the strCurrentUserEmail field to the WorkEmail value of the GetUserProfileByName data connection using the later steps from Itay’s writeup.  It should look like this (Fig 6).


Fig 6 – Setting field to WorkEmail value

What this does is pull the WorkEmail value from the profile database for the user who just opened the form and puts that email address in our designated field.  We could get this same value using the Default value function button on that field, but this would set the value once for the initial submitter and never change.  I leverage this notion in another field named strSubmitterEmail so that I can also check to see if the current user is the original submitter.

strCurrentUserDepartment – Tools > Form Options > Open and Save > Rules.  Add an action that sets the strCurrentUserDepartment field to the Department value of the GetUserProfileByName data connection the same way you did the previous step for WorkEmail. Note: You can add this action to the existing rule for email.

What this does is automatically pull the department of the current user and put it in the designated field.

Add Conditional Formatting to Applicable Controls

grpIT – Double-click this control on the canvas to get to its properties.  Click Display > Conditional Formatting.  Add a condition with two caveats.  The first will check the contact list against the current user.  The 2nd will check the contact list against the current user’s department.

  • After clicking Add, click “Select a field or group” in the first dropdown.  Change the data source to your Contact List, drill down to the data elements, click on E-mail_Address, and select “All occurrences of E-mail_Address” in the bottom dropdown (most people never notice this – Fig 7).


Fig 7 – Choosing All occurrences of a data connection field

For the operand, choose “are not equal to”, and for the last box, choose “Select a field or Group” again.  From your main data source, select strCurrentUserEmail

  • Click the “And” button on the right to add another caveat to the condition.  In this one, select strCurrentUserDepartment from your main data source in the first dropdown, “is not equal to” for the operand, and the text “IT” in the last dropdown.  Be sure to change the “and” on the right to an “or,” and lastly check the box for “Hide this control.”  It should look just like Figure 8.  

Fig 8 – Conditional formatting to hide sections from unintended users

What we are essentially doing is checking to see if the current user is in the overall list of approved users, and then we are breaking it down further to see what department that person is in.  If the current user is not in that list, then the section is hidden.  If the person is in the list but not in the specified department, then the section is hidden.  An alternative way to do the department filter is to make separate contact lists for each sub-group.  If you do it that way, it requires more lists and more maintenance, but it allows you to assign a regular user as the owner of his/her respective list in order to maintain it (removes the burden from us).  If you use one list with sub-categories, then you can’t as easily hand the maintenance over to regular users.

grpFinance – Do the same steps for this section as you did for grpIT except change the text “IT” to “Finance.”  Note: Be sure that the text you type in situations like this is EXACTLY the same as what Active Directory shows.  IT is not the same as it and Finance is not the same as finance.

Here is the final result.  If you reference Figure 4 above, you will see that my department is shown as Finance… 

Fig 9 – Finance user only sees the Finance section

Fig 10 – Manually changed Department to IT (demonstration purposes only)

Fig 11 – IT user only sees the IT section


Fig 12 – Log in as SharePoint Tester account

Fig 13 – SharePoint Tester not in Contacts list and sees nothing

**After it is all working, be sure to remove the text boxes from your form for strCurrentUserEmail and strCurrentUserDepartment, because they are only in this example for testing purposes.  You want to make sure you can see the data that is being put in there during testing.  Once it works, remove those text boxes, or if you want to show them, then make them read-only.

This is my first attempt at any blog post, so please feel free to critique and comment on any errors, bugs, typos, mistakes, fixes, questions, or confusions you may think of…

Posted in InfoPath 2007, MOSS 2007 | Tagged: , , , , , , , , , , | 21 Comments »