Sunday, August 30, 2009

InfoPath: Transfer Data Between 2 Forms

Overview:
When added to an InfoPath Form template, the following JScript allows data to be transferred from one form to another programmatically using code executed by the first form. For example, this can allow a set of data from a forms data sources to be extracted and transfered into another form containing similar fields. This can also allow variations, or custom versions of a form template to be sent to specific people who may speak a different language, require an alternate layout or theme, or if the data containined in the form is confidential and needs to be submitted to a secure or different location to other forms of the same type.

Alternative Methods for Transferring data between forms (without using code)


Requirements:
- InfoPath 2007 (can also be acheived using 2003)

Process:
The step descriptions below have been commented out to allow them to be pasted into the forms code. Additional notes are in blue and have also been commented, but can be ommited if required.
There are a few ways you can get the code to run. The easiest would probably be an event handler function associated with a button on the form, as the function is generated by InfoPath when you select "Edit form code" from the "Button Properties" dialog. Other options are to add the code to the submit function, which is executed by InfoPath when the form is submitted. If using "Rules and Custom Code", a combination of rules and the example below can be used to submit both form #1 and #2.





/* -----------------------------------------------------
JScript: Transfer data between two forms
22nd Feb 2009
-------------------------------------------------------- */



//1. Set the path to the "form #2" template:

var strNewFormPath = "http://path-to-infopath-form-template";


/*
Note: If the path to the form template is a UNC path ("file:///\\filesrv06\users\john\Forms\Form2.xsn"), the backslash "\" is a special character which is used to escape other special characters, including the backslash it'self. The address above will actually be interpreted as "file:///\filesrv06usersuserFormsorm2.xsn", or similar which will result in the following error: "The following URL, path, or file name is invalid".

To ensure that all characters in the address string are interpreted correctly, the backslash "\" character needs to be escaped for it to remain in the string (see below):
"file:///\\\\filesrv06\\users\\john\\Forms\\Form2.xsn" will be interpreted as "file:///\\filesrv06\users\john\Forms\Form2.xsn" when executed.
*/




//2. Open the second form:
var objNewForm = Application.XDocuments.NewFromSolution(strNewFormPath);
/*
Note: This will result in InfoPath opening the second form from the address supplied in step 1. If you recieve a runtime error at this line in the code, check to make sure that special characters have been escaped, and that the location of the form template is accessable to all users of the form.
*/




//3. Set the name spaces for the new form:

objNewForm.DOM.setProperty("SelectionNamespaces", 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-01-29T23:32:25" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"');

/*
Note: To find the name space for a data source, go to the properties of a field in the data source, then the details tab. The name space in the details tab should be all that you need.
You will need to use the name spaces from your data sources, instead of the examples above (and in step 5).
*/




//4. Load the XML Document of "form 2":
var objExternalData = new ActiveXObject("MSXML2.DomDocument.5.0");objExternalData.validateOnParse = false;objExternalData.loadXML( objNewForm.DOM.xml );
/*
Note: This loads the XML Document of the second form's main datasource, assigning the DOM Document to a variable which is then used in step 6 to access the second form's data source from the first form.
*/




//5. Set the name space for the XML data object:

objExternalData.setProperty("SelectionNamespaces", 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-01-29T23:32:25" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution" xmlns:ns1="http://schemas.microsoft.com/sharepoint/soap/directory/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"');




//6. Update the value of fields in the main or secondary data source of "form #2" with values from "form#1":

objNewForm.DOM.selectSingleNode("/my:myFields/my:Name").text = XDocument.DOM.selectSingleNode("/my:myFields/my:Name").text;
objNewForm.DOM.selectSingleNode("/my:myFields/my:Description").text = XDocument.DOM.selectSingleNode("/my:myFields/my:Description").text;

/*
Note: The above two lines will copy the values from the Name and Description fields in Form 1 to the Name and Description fields in Form 2.
The "objNewForm.DOM.selectSingleNode..." selects the required field in the secon form, which is then assigned the value from the corresponding field in the first form: "XDocument.DOM.selectSingleNode..."
*/


Alternative Methods for transferring data between forms without using code:

If using SharePoint you can submit the data to a SharePoint list from the first form eith using a CAML query and the SharePoint lists web service or the forms main submit data source, then load the data into the second form from the SharePoint list using a secondary data connection. If not using SharePoint, this can also be achieved by submitted to an external database (Access) or even an xml file (default) which can then be used as a secondary datasource in the second form to retrieve the data.

Wednesday, August 19, 2009

SPD Workflow - Test if value exists in any item in SharePoint list - create new item if not found

SharePoint Designer Workflow: How to test if a specific value exists in any item in a list without the workflow stopping due to a "List item not found" error if no items exist with the required value.

When trying to find a list item using the "Update List Item" action or similar in a SharePoint Designer workflow by matching a field which is not always unique (eg. the "Title" column/field), the workflow will stop if the list item is not found with a "List item not found" error. To prevent this, a looping workflow can be used to build a delimited string containing the value from the field being tested, for all items in the list.
Instead of trying to test if a specific value exists in any item in a list by testing the required field directly, the workflow can compare the string containing all possible values using a much larger range of useful conditions including "contains", "does not contain", "contains (ignoring case)", which can be used to test if the required value exists. If the value is not found, the workflow will continue as normal without causing an error as only a simple string compare had taken place.

This can be quite useful if you want the workflow to do one action if an item is a seperate list containing a specific value is found, and another action if not found (without stopping due to workflow error). This can be used to test if the is an item already exists in the list containing a specific value, and to use this item if found. If the item does not exist, then one is created (example/scenario below).

SharePoint Designer does not provide standard functionality to create a looping workflow, but it can be achieved using two separate lists with on-change workflows that trigger each other. A "flag" is set (Boolean) to determine if an item has been processed by this instance of the workflow, and used to find the next item to be processed. Once updated, the on-change workflow can either pause for a duration to allow the remaining items to be processed before resetting the flag, or a similar workflow can loop back through to reset each item.

The article Service Pack 2 prevents an on-change workflow from starting itself demonstrates how to create looping workflows using SharePoint Designer, but also provides important information about the difference in Workflow functionality between Service Pack 1 and Service Pack 2 for MOSS 2007. If you had looping worklfows functioning prior to upgrading to service pack 2, they may not work if the loop was being controlled from a single on-change workflow for this reason.

Example: Update an item if one exists with a specific title, or create/add a new item to the list if an item is not found with the required title field.


  1. Using a looping workflow, append the Title from each item in the required list in a separate list item to a string field separate to the items being processed.
  2. In the main workflow, build a dynamic string containing the required title value. Note: The "Build a dynamic string" action allows fields of different data types (Dates, People, Numbers) to be converted into a string and concatenated if required.
  3. Using the "Compare any data source" workflow condition, test if the required value is, contained in the string of all possible titles.
  4. If the title does not exist in the string, the workflow can then create a new item. If the title does exist in the string, then the workflow will be able to find the list item to be updated and won't stop due to the "List item not found error"

Related Posts:

SharePoint Looping Workflow - How to: Loop through and process all items in a list
"The OOB workflow actions provided by SharePoint don't allow a loop to be configured explicitly. Instead, a number of workflows can work together to create a looping affect. Another limitation of Workflows in SharePoint using SharePoint Designer (SPD) is the inability to simply test if the user who initiated the workflow is a member of a SharePoint group, or to test if the value of a field in the item which initiated the workflow is equal to the value of a specific field from any item in a separate list."


How to wait for a change in any list, wait for multiple field changes in the current item (SharePoint Workflow)

This article describes techniques which can be used when developing workflows in SharePoint using SharePoint Designer. They allow a workflow to wait for a field change in an item in another list, or to wait for multiple field changes in the current item before continuing.

Looping Timer Workflows
To have a looping timer workflow (eg. send a daily notification/reminder until a specific condition is met), the workflow must start when an item in the list is changed, and when it is created depending on the scenario.

How to configure a workflow to start at specific time, then loop / repeat periodically (Daily, Weekly)The following method can be used to start a workflow at a specific time, then repeat periodically (each day). Periodic Workflow Processing: (send daily email notification or reminder)A useful implementation of this technique allows you to configure workflows to run as background tasks at a specific time instead of being triggered by a user manually, or after creating or modifying a list item.


SharePoint Workflow Errors: Descriptions, resolutions and WorkaroundsThe following table lists some of the common errors that can occur in a Workflow developed using SharePoint Designer. A short description of some of the likely causes for each error are also provided.

Saturday, August 8, 2009

InfoPath Coding Tips - When to use code in InfoPath forms

When should code be used in an InfoPath form and when should it be avoided?

There is no simple answer to this question, as it comes down to a matter of personal preference. This article is aimed at reducing the development time for InfoPath forms of various scales. The following are some tips to help you make the right decision.

Firstly, I should note that InfoPath is a great tool for creating electronic forms, as many features are provided to including data connections to external sources (Database, SharePoint, etc.), data validation and conditional formatting which allow complex forms to be created and submitted without using any code.

I my opinion, as an InfoPath form becomes more complex the efficiency of the form's development is reduced when avoiding using code. This is due to the amount of mouse clicking required to set default values, create rules and apply formmating conditions to individual elements in a data source, or controls on the form template. If code is not a strength and you don't mind a bit of clicking, then this probably isn't a bad way to go as it does have a major benefit which is often overlooked: The Logic Inspector. If all, or most form functionality can be created without using code, the Logic Inspector will reflect the amount of detail put into the form's design as well as giving an overview of any functions if code is used. It allows you to see at a glance, as well as print details of any validation, field calculations, rules or programming used accross the entire form.


How can development time and effort be saved when designing InfoPath form which require code?

Code is Reusable
InfoPath form code can be written to allow reuse in multiple forms which may have completely different requirements for functionality and layout. Developing to enable code reuse will prove to be a significant benefit to any developer. Having access to code that you know that works as well as an intermate understanding of how it works will save a many hours of development, as well as providing building blocks for further development.

It will take longer during the initial stages to develop forms using code, but as you gain experience and start build a "bank" of reusable code, development time will significantly decrease.

If developing a set of forms, starting from a common template with the layout and theme already applied to the form can also reduce development time as well as enhance the proffessional apperence of the set of forms.

Choose an appropriate language to become most familure with
Many languages are supported when using InfoPath forms (JScript, VBScript, C#, VB), sometimes making it harder to find relevant information or resources when troubleshooting and learning. Some languages are more powerful than others in the functionality offered, or the ease of coding. You should try to use the same code language between different forms which are developed as it allows for code reuse and a steeper learning curve. C# is the most recent and provides the greatest set of core functionality followed by VB. VBScript and JScript offer less, but are very common and easy to code in terms of syntax strictness.

No need to over do it!
After saying all this, I should stress a few key points:


  • If a form is simple code may not be required. If a form doesn't require complex validation, formatting and rules, as well as not having a large number of fields in the main data source it should be quicker to set up using the tools provided InfoPath.
  • It does take time to learn how to use code to enhance form functionality and reduce development time for complex forms. Don't dive straight in the deep end; break up what you are trying to do, then learn and implement individual components as required. Individual components developent in a separate form can be saved in a separate location easily for use in future form development.
  • Reuse Code and Form layout. Write code in ways that make it reusable. Create snippets and forms containing individual functions, or a set of related functionality to start building up a "bank" of resources. Reuse a previous form's layout as a starting point for aesthetics when developing a form set, or forms which incorporare company branding.

Saturday, August 1, 2009

InfoPath Performance for SharePoint Data Connections

When an InfoPath form has a large number of SharePoint data connections, the time it takes to open a the form will increase resulting in slow loading time when the form is being opened. To reduce the loading time of the InfoPath form, SharePoint list/library Views with filter criteria can be used to minimise the number of results, while ensuring that all required items that are displayed in the result set.

[edit]
InfoPath Data Connections to a SharePoint list retrieve items from the list's default view. This can lead to the data connection not returning the required result from the SharePoint list if items are filtered or limited. See InfoPath data connection not returning all results from a SharePoint list for details.

For instructions in how to create and set up InfoPath data connections to retrieve data from SharePoint lists, see Using Secondary InfoPath Data Connections to retrieve data from a SharePoint List or Library.

The challenge when creating views to ignore irrelevant items is determining the filter criteria required that will display the smallest number of results possible, while at the same time ensuring that all required results are displayed. For Example, a data connection to a task list may only need to retrieve data from completed tasks, so the default view can be set to only display completed tasks, or the data connection can be linked to a specific view in the list (not the default) which displays the require completed items.

In most cases, recently created or modified items will be the most relevant.I commonly use SharePoint list view sorted by the Item ID in descending and limit the number of results to the required amount order limited to a specific number such as 100 or 200, which will return the items most recently added to the list. To ensure the InfoPath data connection retrieves the 200 most recently modified items, the filter criteria for the view should be set to sort by the Modified date in descending order, and the number of results limited to 200. Using either or a combination of the above two methods will ensure that any item or document/form recently created or modified will be available in the data connection's data source from the InfoPath form. This method will be most effective when the SharePoint lists used in the form as secondary data sources have a large number of items as well as there being data connections to multiple SharePoint lists. I have found that once there are 3 or 4 data connections or more retrieving data from SharePoint the loading time starts to slow when opening a new form.

List View Sort and Filter Criteria Examples:

The image below shows the sorting criteria required to display items in Modified date order, with the most recently modified file at the top.







The image below shows the sorting criteria required to display items in the order of creation, with the most recently added file at the top. This can also be achieved using the Created date column/field in the SharePoint list.








The Image below shows the required setting to limit the number of results in the SharePoint list view to 100. Set this value to a number which is large enough to return all required items in the InfoPath data connection, but not too large as this has an impact the forms performance when loading
data from data sources.






As the limit is reduced performance will increase, but risks not displaying all required results from the SharePoint list.