SQL Server 2005, also known as Yukon, comes with greatly improved XML support. Just look at it: native XML columns - store XML blobs in your records, along with other data types. These XML columns can be typed or untyped; typed here refers to XSD typing, which provides backend data validation. If an XML blob that you're trying to put into an XML column doesn't comply with the schema associated with the column, the insert will fail. Cool, huh?
There's more cool to it. Meet XQuery - a query sub-language of SQL that can be used to query your XML columns. What does this mean to you? It means that you can do a structure-aware search through XML.
Imagine: you need to create a training management system. It's a system with a non-trivial schema - each employee will need to take some mandatory courses, there will be education fields for their secondary education... One of the reports you must generate from the system is "show all employees that graduated before year X". How would you have done this yesterday?
You could create your InfoPath form against a relational database. this would mean that you'd need to start with ERD design (looong... and messy - not all XML structures translate nicely into relational systems: think of choice, recursive, optional sections). Report generation would have been easy afterwards: just do "SELECT employee_id FROM employees WHERE ...". You all know SQL, no need to go too deep here. But recognize the pain you would have to go through with this approach: ERD design, shredding of the XML structures into relational structures. Plus, if you need to make changes to the schema, this becomes painful: non-trivial changes to relational systems are tough.
You could create an employee profile management form in InfoPath, and store the resulting XML blobs in SharePoint. You'd pull in basic employee data - names, positions, hire dates - from your HR database (let's assume it lives on a separate SQL database). But how would you generate that report? Built-in SharePoint full-text search is obviously not an option here. What you'd probably do is create a custom app that reads in the XML's, parses them, verifies the criteria ("graduation date > X"), and if the criteria is satisfied, spits out the employee id. Scary and complicated.
Entering today. XML Columns, XQuery and InfoPath.
Jeez, that sounded too much like a marketing slogan :-).
What you can today is create an XML column and store entire InfoPath there. No ERD design. Just drop an entire form (one record) into a SQL column. Then, when you want to report on several forms, just use XQuery.
This not only allows you to answer trivial queries like "show all employees that graduated before year X", but perform true heterogeneous query. Recall: the basic HR database is a separate relational system. The training management system you just built stores XML blobs. How do you connect the two? Just do a JOIN like you would have otherwise! Yes, SQL Server 2005 allows you to do joins between relational and XML data!
It's hard to underestimate the benefits here. Structure-aware search will frequently give you much better search results, if you know what you're searching for. It can answer semantic queries that full-text search can't answer - and you don't need to shred your data into relational structures.
You're probably wondering how exactly do you make InfoPath store data in an XML column in Yukon.. Coming soon, in blog theatres near you :-). UPDATE: the next chapter of the story is here.
Alex WeinsteinProgram Manager
If you've ever designed and deployed a form that will be frequently used or require significant data analysis, you have probably looked into maintaining data in a SQL database. With InfoPath 2003 and the InfoPath 2007 rich client, you get what you expect. You create a main database data connection to the SQL server and pick tables and columns that meet the requirements for submit functionality. When you open your form and click the "Run Query" button, you see the data pulled from the database as you'd expect. You then happily insert, update, or delete records and, when the time is right, hit "Submit". Luckily for you, the InfoPath client took care of maintaining the list of changes that you made while editing your form. With this list of changes intact, your updated data streaks back to the database to await the next query.
Enter InfoPath Forms Server... Here we don't get the change tracking for free, so we'll need to do some work to simulate change tracking outside of the form's execution. Basically, what we're going to try to accomplish is to use an intermediate web service that will handle querying and submitting the data from and to the target database. The web service will timestamp the data at query time and send the data to the form for editing. Then the form filling user will edit the data and click "Submit". When the data arrives back at the web service, we need to figure out what changed in the meantime. This means that we'll have to check to see if anything has changed in the database since the time when we queried the data. If it has, then the submitted data should be rejected and the user should re-query before re-applying her edits. If it hasn't, we'll diff the submitted data with the database data and submit the difference back to the database! Let's get started!
Create the Web Service and Setup the Database
Since the InfoPath data connection wizard is easiest to use when your web service is already established and available, let's start with creating the web service and setting up the database.
1) Download the attached archive and extract it somewhere on your hard drive
2) Create a new web site in Internet Information Services (IIS)NOTE: IIS must be enabled as a Windows Component through "Add or remove Windows components" in the "Control Panel")
3) Create the web service
4) Add the code and service asmx files to the project
5) Customize the web service code for your database
DBData(parameter_list)
UpdateDBData(DataSet, parameter_list)
6) Create the database table and DML triggerThe web service includes logic to update the database table and create a DML trigger to maintain a timestamp of Last Update for each record. However, you may want to create the timestamp column and trigger yourself.
7) Build the Visual Studio solution and publish the web site
Design the InfoPath Form Template
Now that we've setup our database and constructed our web service to do the querying and submitting for us, it'll be a breeze to design an InfoPath form template based on the web service.
1) Design a new, browser-enabled form template, based on the web service that will query/submit the DataSet.
2) Set the default values for the "ID" and "QueryTime" fields
3) Insert the controls into the View.
4) Publish the form template to your InfoPath Forms Server
At this point, you have a form template that will work correctly when you open it in the InfoPath rich client. But this post is all about getting things to work correctly in the InfoPath Forms Server. So you'll need to configure your data connections to work in the browser by converting the main query and submit data connections to use Universal Data Connection (UDC) files in a Data Connection Library (DCL). Now you should be all set. The web service will query and submit the data to the database, and we'll make our best attempt at a diff of the database data against the submitted data.
From here on out, it's up to you. If you want to, for example, modify the database structure or change the way the trigger works, then you're going to need to modify the web service code. You'll also need to use "Convert Main Data Source" to update your form template whenever you modify your web service. You might also want to add support for multiple tables. All this will take some exploration of ADO.Net DataSets, but it is a reasonable exercise as long as you're comfortable writing managed code.
Forrest DillawaySoftware Design Engineer in Test
A few folks put together good resource compilations of everything InfoPath-related: articles, screencasts, help topics... Check them out:
1) InfoPath 2007 resources by Joris Poelmans
2) Office 2007 Spotlight: InfoPath 2007 by Michael Gannotti
3) Building Web Forms with Office InfoPath Forms Services by Dave Glover
Alex
Scenario
A school department wants to create a standard digital template to use when administering tests to students. Since the template is to be a standard format across multiple classes, the department requires that teachers be able to enter questions appropriate to their individual classes. To simplify things, the department decides to allow three types of questions: True/False, Multiple Choice, and Free-Form Essay (write-in). So, in short, teachers create questionnaires for the students, determining what type of answer to collect for each. The form is then given to the students taking the test, who step through the questions one-by-one. After the test, the teachers compile the answers, creating a master form for grading. The two main views of the form will look similar to the following:
Wizard-Style Form: One Question at a Time
The heart of the wizard-like functionality of the solution to this scenario is the use of an index counter by which a view is then filtered when the form is being edited. The "Next" and "Back" buttons we see in so many cases appear on this InfoPath solution but they simply change the value of the counter, adding one to the index if "Next" is clicked, subtracting one if "Back" is clicked. In this case, the index counter is placed on the repeating section that is the container for test questions in this form.
Data Source
We will use a repeating group of questions; each question will have a questionText (what's being asked) and one of the following subnodes (implemented as a choice group):
1) trueFalse: keeps track of the student's answer to this question, if this question is a true/false question. Boolean.
2) writeIn: keeps track of the student's essay answer to a write-in question. Text or Rich-Text (XHTML).
3) multipleChoice: we need to remember two things here:
- possible choices (provided by the teacher; repeating group of text fields)
- student answer
Since we want to show students only one question at a time, we will need an auxiliary index field to remember the current question that's being shown. The index counter used by the filter is a field that does not take any direct user input. Give the field a value of 1, which will then be incremented using the buttons.
All-in-all, the data source looks similar to the following:
Views
This forms solution is structured around a repeating section field that appears in both views. To create the duplicate repeating sections, create two views and place a repeating section in the first view. Next, open the second view, open the data source task pane, and drag the repeating section field onto the canvas.
To show the students one question at a time, we need to apply a filter: open the student view and then open the Properties of the repeating section in that view. Click the display tab and then click the "Filter Data…" button. Since we will set the counter to be the question number, and since we want to display only the current question, set the filter to display data for which index = position().
Navigation among the questions is enabled by "Next" and "Back" buttons included in the student view. Insert two buttons into the student view. Double-click the first button: Select "Rules and Custom Code" in the action menu, give the button the label "<< Back" and click the "Rules…" button. Add an action as appears below:
For the "Next >>" button, follow a similar procedure as for the back button but add 1 to the value of index in the above dialogue.
Now we need to take care of the actual question display: each question requires a serial number, the text of the question, and the field for response (which could be one of several pre-defined types.) The teacher's view contains user-editable fields for question text and a choice of answer type; the Student view displays the text of the question and contains the editable response field.
In detail:
Question Text: collected through a Text Box in the Teacher view and then displayed using an Expression Box in the Student view.
Response data is contained in a choice group. The Teacher selects the most appropriate of the three response types permitted by the form and, in the case of multiple choice, adds the necessary choices to a numbered list. No "answer" data field appears in the Teacher view of any of the answer types because all the teacher need do is choose the type of answer. The default Choice Group appears with two Choice Sections but can contain as many as necessary, simply insert the Choice Group and then add more Choice Sections. For this scenario, add the Choice Group and Sections to the Teacher view and then label the Choice Sections with the appropriate answer type. For the multiple-choice Choice Section, add a Numbered List control to the section to contain the options for any multiple-choice section.
The controls to hold student responses to questions are contained in a Choice Group placed into the Student view by dragging the existing Choice Group into that view from the Data Source Task Pane. This action creates a mirror of the Choice Group structure contained in the Teacher view but without the controls or text placed into the Teacher view. Into the Choice Sections in the Student view place, respectively, a set of 3 Option Buttons for True/False/I Don't Know, a Rich Text field for written response, and a List Box for multiple choice. This last has the slight complication that we want to pull in the options the teacher set for the particular question. To do this go to the "Data" tab of List Box Properties and select the second option under "Data": "Look up values in the form's data source." Select the field that holds the values from the Numbered List and these will populate the List Box for each multiple choice question.
To display the question number, add an expression box that displays the value of the index. Type "Auto" into the width property of the expression box and the control will size itself to the value. To display the total number of questions, use an expression box in which you use the following formula where the fields used are the Choice Sections within the Choice Group used to contain responses:
The basic mechanics of this test form are now complete. What remains to be set up are things like submission and review options and settings. Some examples of possible additions to this scenario are as follow:
The sample form template that has this technique is attached; make sure to download the XSN to your computer before opening it. Note that this technique works in InfoPath 2003 and 2007, but will not work in browser-enabled form templates.
JonathanProgram Manager
Thanks to our brilliant ex-colleague Ned Friend for building the sample form template.
With the introduction of InfoPath Forms Services for MOSS 2007, clever management of form template deployment will probably become a must for most IT departments. You'll want to be sure that form templates are not draining server resources. You'll especially want to keep an eye on administrator-deployed form templates, as those can achieve fully trusted status and execute arbitrary code on the server.
With that in mind, it's probably a good idea to set up a code review process for InfoPath form templates that will be deployed by the administrator. To facilitate the process, it might be nice to have a tool around that will tell you whether or not a form template uses custom code. This is pretty easy to determine, and a tool can be coded up rather quickly, but we figured we'd facilitate the process and provide a sample to get you going. And here it is…
using System;using System.Collections.Generic;using System.Text;using System.Xml;using System.Xml.XPath;using System.IO;using System.Diagnostics; namespace CheckForCode { class Program { /// <summary> /// The Main method entry point for the code-checking algorithm. /// </summary> /// <param name="args">The command-line arguments for the code-checking algorithm.</param> public static void Main(string[] args) { if (args == null || args.Length == 0) { Console.WriteLine("No arguments specified."); } else { string filePath = args[0]; try { Uri fileUri = new Uri(filePath, UriKind.Absolute); filePath = fileUri.AbsoluteUri; // If the file is an http URL, download it to the local machine. if (fileUri.Scheme.Equals(Uri.UriSchemeHttp)) { filePath = CopyFormTemplateLocally(filePath); } if (File.Exists(filePath)) { string extension = Path.GetExtension(filePath); if (extension.Equals(".xsn", StringComparison.CurrentCultureIgnoreCase)) { // Extract the xsf and check for the root assembly. string pathToXSF = ExpandManifest(filePath); CheckXSFForCode(pathToXSF); } else if (extension.Equals(".xsf", StringComparison.CurrentCultureIgnoreCase)) { // Check for the root assembly. CheckXSFForCode(filePath); } } } catch(ArgumentException exn) { Console.WriteLine("The file path argument is invalid."); Console.WriteLine("Exception message: " + exn.Message); } catch(UriFormatException exn) { Console.WriteLine("The file path is not a valid Uri: '" + filePath + "'"); Console.WriteLine("Exception message: " + exn.Message); } } Console.WriteLine("Hit any key to exit."); Console.ReadKey(); } /// <summary> /// Get the path to the temp folder for the current user. /// </summary> private static string TempFolder { get { string tempFolder = Environment.ExpandEnvironmentVariables("%temp%"); return tempFolder; } } /// <summary> /// Copy a form template at an http URL to a local path. /// </summary> /// <param name="absoluteFileUri">The absolute Uri of the form template.</param> /// <returns>The local path where the form template was downloaded.</returns> private static string CopyFormTemplateLocally(string absoluteFileUri) { string fileName = Path.GetFileName(absoluteFileUri); string tempFilePath = Path.Combine(TempFolder, fileName); // Download the form template source from the server. System.Net.WebClient client = new System.Net.WebClient(); client.UseDefaultCredentials = true; client.Headers.Add("Translate:f"); client.DownloadFile(absoluteFileUri, tempFilePath); return tempFilePath; } /// <summary> /// Expand the manifest.xsf file from the specified xsn. /// </summary> /// <param name="pathToXSN">The absolute path to the xsn.</param> /// <returns>The path to the expanded xsf.</returns> private static string ExpandManifest(string pathToXSN) { string tempFolder = TempFolder; Process expand = new Process(); expand.StartInfo.ErrorDialog = false; expand.StartInfo.UseShellExecute = false; expand.StartInfo.RedirectStandardOutput = true; expand.StartInfo.CreateNoWindow = true; expand.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; expand.StartInfo.FileName = "expand.exe"; expand.StartInfo.Arguments = pathToXSN + " -F:manifest.xsf " + tempFolder; expand.Start(); // Note that the xsf may not be named "manifest" so this could fail if the user // has extracted the form template files and changed the name of the file. return Path.Combine(tempFolder, "manifest.xsf"); } /// <summary> /// Check the xsf at the specified path for a root assembly dll. /// </summary> /// <param name="pathToXSF">The absolute path to the xsf document.</param> private static void CheckXSFForCode(string pathToXSF) { string rootAssemblyNameXPath = "/xsf:xDocumentClass/xsf:package/xsf:files/xsf:file[xsf:fileProperties/xsf:property/@value='rootAssembly']/@name"; // Load the xsf document. XmlDocument xsfDocument = new XmlDocument(); xsfDocument.Load(pathToXSF); // Load the xsf namespace. XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(xsfDocument.NameTable); nameSpaceManager.AddNamespace("xsf", "http://schemas.microsoft.com/office/infopath/2003/solutionDefinition"); // Navigate to the root assembly, if it exists. XPathNavigator xsfRootNavigator = xsfDocument.CreateNavigator(); XPathNavigator assemblyFile = xsfRootNavigator.SelectSingleNode(rootAssemblyNameXPath, nameSpaceManager); // Alert for code review. if (null == assemblyFile) { Console.WriteLine("No custom code in form template."); } else { Console.WriteLine("Code review required! Root assembly name: " + assemblyFile.Value); } } } }
using System;using System.Collections.Generic;using System.Text;using System.Xml;using System.Xml.XPath;using System.IO;using System.Diagnostics;
Just slap this into a console application in Visual Studio 2005, and you'll have a simple application that will accept the Uri of the form template or xsf as input and output "No code" or "Code found!" With a little customization, something like this could be worked into a workflow that would govern the deployment of administrator-deployed form templates.
And taking it a bit further, you could automatically seek out the source code folder in the "manifest.xsf" file, in the "projectPath" attribute of the "xsf2:managedCode" element. Note here, though, that it will only be accessible if the form designer stored the VSTA project in a shared location, so you may have to implement some administrator policies to guarantee that this location is accessible.
I'd love to compile a list of blogs about InfoPath to help the developer community connect and share insights. If you wrote at least one InfoPath article in the past, and plan on writing more, please leave a link to your blog in the comments.
Expect an OPML compilation in a week or two!
UPDATE: OPML compilation is here.
Lately, we've had a lot of interest in e-mailing a custom view with InfoPath forms that are submitted via e-mail. There are a few simple tricks that will allow you to do this.
Before we start, note that, in the InfoPath rich client, you have the option to "Send to Mail Recipient" from the file menu in the Editor. In this case, you're stuck sending the currently active view of the form. The user filling the form would have to manually click or change data in order to fire an event to switch to a custom view. While this is feasible, we can do better with a pre-defined e-mail submit data connection.
To define an e-mail submit data connection in the InfoPath Designer:
Click "Tools" >> "Data Connections…"
Click "Add…"
Select "Create a connection to" >> "Submit data" and click "Next >"
Select "As an e-mail message" and click "Next >"
Enter an e-mail address in the "To" header field, or bind it to a field in your form template.
Fill out any other e-mail header information and finish the wizard.
Click "OK" / "Finish" / "Close" to get out of the wizard and finalize your e-mail submit data connection.
Now that we've defined the e-mail submit data connection for our form template, we can move on to the custom view portion…
The easiest option is to send a blank view. To accomplish this, you'll simply want to switch views before you submit. This is easily accomplished using a rule on button click. Here are the steps, in the InfoPath Designer, to configure the "Main Submit" toolbar button to send the blank view:
Create a blank view
On the "View" menu, click "Manage Views…"
In the Views TaskPane, click "Add a new view…"
Type a name for the view and click "OK".
Configure main submit to submit the blank view with the e-mail
Click "Tools" >> "Submit Options…"
Check the "Allow users to submit this form" checkbox.
Select the "Perform custom action using Rules" radio button.
Click the "Rules..." button.
Click "Add..." in the "Rules for Submitting Forms" dialog.
Click "Add Action..." in the "Rule" dialog.
Select "Switch Views" and select the blank view in the "View" drop-down list box.
Click "OK" to close all the dialogs.
Now, when the user clicks "Submit", the view will first be switched to the blank view, and then the form will be submitted to the mail recipients. InfoPath sends the active view contents in the body of the e-mail message, so the blank view will be sent in the message body!
But now the next obvious question is, "Wait a second, I thought we were sending custom views, not just blank ones!" Good call. InfoPath Forms Services treats the "switched-to" view a bit differently than the InfoPath rich client. In browser-enabled form templates filled out in the browser, you can add controls, text, pictures, etc. to the blank view to which we switched before submitting, and the message body will display the data in the custom view, along with the Introduction specified in the e-mail submit data connection wizard. In the InfoPath rich client, you'll still only see the blank view due to view-switching concurrency limitations. So we need an alternate solution…
Basically, instead of e-mailing a custom view, we'll e-mail custom view content. We'll have two sections in one view: one to hold the controls where the user can fill out the form, and one where the custom "view" contents will be stored. Then, at submit time, we'll run a rule to first hide the editing section and show the custom e-mail body section, and then submit via our pre-defined e-mail submit data connection. This works identically in the browser and the InfoPath rich client Editor. Here are the high-level steps:
Insert two "Section" controls into the form view. Name one "EditSection" and the other "EmailSection".
Fill the sections with the relevant controls, formatting, etc. Create your "custom view" inside the "EmailSection" and create the normal form-filling "view" in the "EditSection".
Create a "True/False (boolean)" data source node. Name it "ShowCustomEmailSection", and set its default value to "FALSE".
Add conditional formatting to hide and show the "EmailSection" and "EditSection" sections.
Set the "EditSection" conditional formatting to "hide this control" when "ShowCustomEmailSection" is TRUE.
Set the "EmailSection" conditional formatting to "hide this control" when "ShowCustomEmailSection" is FALSE.
Configure your submit button as above with the blank view case, but, instead of adding a rule action to switch views before submitting, add a rule action to set the value of the "ShowCustomEmailSection" field to the "true()" function. This will conditionally hide the "EditSection" and show the "EmailSection". All that will show up in the message body is an HTML rendering of the contents of the "EmailSection".
And that's it! Note that you may have to set the "Postback Settings" for the relevant controls to "Always" for browser-enabled form templates to get the conditional formatting to work as expected.
The SharePoint list data connection in InfoPath is a great declarative way to bring in data from a SharePoint list, but it does have some limitations. For those willing to put in a little extra effort, there’s much more that can be done with SharePoint lists: you can bind to views based on these lists. Here are the steps for creating the connection to a list view.
First, let’s get the URL:
1. Navigate to the SharePoint site that contains the list, for example: http://contoso/sites/sales/Sales%20Contacts/Forms/AllItems.aspx 2. Go to “Modify settings and columns” 3. Copy the List={GUID} portion of the URL and paste this into a buffer like a Notepad window. 4. In Notepad, create the following URL (the blue portion us taken from the step 1 URL, and the red portion must be added.
http://contoso/sites/sales/_vti_bin/owssvr.dll?Cmd=Display&List={GUID}&XMLDATA=TRUE&noredirect=true
This will return an xml file that can be used in an XML file data connection, as if it came from a file system. After this, you can use the URL as the location of an XML data file when creating a data connection.
Two caveats: - Form users must have read access to the SharePoint list. - During creation of the data connection, do not include the file in the form template, as it should be dynamically generated from the SharePoint list.
Some tricks: 1. When you’re in “Modify settings and columns,” if you click on one of the views in the list at the bottom, you should note that the URL is “enriched” with &View={ANOTHER_GUID}. If you would prefer to use the columns from that view, you should similarly enhance the URL you use above. 2. You can also use the url to filter data rows based on column values. For example:
http://contoso/sites/sales/_vti_bin/owssvr.dll?Cmd=Display&List={115BC7B7-0A82-403E-9327-F3C73E6D37F3}&XMLDATA=TRUE&noredirect=true&FilterField1=xd__x007b_52AE1EF8_x002d_28E7_x002d_4CE4_x002d_AE23_x002d_54E23E80DDB5_x007d_&FilterValue1=Approved
Note: be sure to remove the “ows_” from the beginning of the FilterField ID.
With this filter, the XML file returned will be filtered to only display those projects that have been approved. Without the green portion, you would see all the projects.
In order to populate other fields with data from WSS, you create the secondary data source just like above, then in form code or script, you can use GetDOM(“dataSource”) and walk the DOM normally, updating the main DOM as appropriate.
Ed Essey Program Manager
It's Friday, and on Fridays I usually try to dig up a cool article or two from the community
1) Patrick Tisseghem wrote a beautiful walkthrough on making browser forms show up in a web part - no code required, just follow the screenshots.
2) S.Y.M. Wong-A-Ton published a very detailed paper on saving InfoPath forms to a SQL Server 2005 XML column. This is a very cool integration scenario that enables powerful data analysis using XQuery, and even crazy things like joins between your XML form data and LOB data stored in a relational system. Be sure to check it out!
What are Roles? Without going much in detail, InfoPath roles is a functionality where you can define user tags like "Sales", "Management" and utilize them in your form logic. This enables some very interesting scenarios in the forms space. For a detailed discussion on this topic, take a look at this MSDN lab. If you have worked with InfoPath 2003, you would notice that Roles have not changed much in 2007, and that they are not supported by InfoPath Forms Services. My focus will be in how we can enable role-related scenarios in browser forms.
For the purpose of this article, lets borrow the scenario from the lab. - "The management team at Contoso Corporation reviews each of the Sales Report filled out by sales representatives. Because the management team is interested only in sales deals that exceed a certain amount of money, your department is asked to add an additional view to the sales form that shows only those deals"
STEP 1: Find a way to store role-related data
You can store information about which users belong to which grounps in an XML file, included as resource as a part of the XSN. Here's one way to organize this XML file:
<?xml version="1.0" encoding="utf-8"?> <roles> <role> <name>Sales</name> <users> <username>john</username> <username>jane</username> </users> </role> <role> <name>Management</name> <users> <username>bill</username> <username>abby</username> </users> </role> <role> … </role> </roles>
Create a data source pointing to this resource file and use this data source to make decisions in step 2.
Variation: Roles and Users relationship might be stored in a database (say HR system). You would then create a secondary data source connecting to your HR System instead of the XML file mentioned above; everything else stays the same.
STEP 2: Determine the role of the current user
1. Add hidden fields to the main data source of your form. These will store:
2. Set the detault value of CurrentUser to the username() function.
3. Set "CurrentRole" value to
name[username = CurrentUser]
STEP 3: Use rules and CurrentRole
To accomplish our scenario, we will create two views: one for "Sales", and one for "Management". Using Rules, you can switch to the appropriate view on load of the form:
1. With the form template in design mode, on the Tools menu, click Form Options.2. Click the Open and Save tab, and then click Rules, and the following two rules:
And that's it! You can use CurrentRole the same way you'd have used Roles in the InfoPath smart client. Note that this trick works on the smart client, too - so if you want to create a roles-based InfoPath application, this method will help.
Pradeep RasamProgram Manager
Template parts allow a form designer to combine view information, rules, schema, default data and other compatible components of a form template into a package that can be distributed to other form designers and inserted into form templates without manual recreation. Data connections, with some restrictions, are a compatible component that can be included in a template part.
Adding a data connection to a template part is the same process as adding a data connection to a form template, with one exception - data connections in template parts cannot submit data. Once added to the template part, the data connection is added to the form template upon insertion. When inserted, the data connection name will be appended with the template part name, identifying the data connection as originating from the template part. The unique name of the data connection is used to identify the data connection during insertion and updating of the template part. When a template part with a data connection is inserted, the data connections are searched for the data connection name. If found, the data connection is removed and replaced with the data connection in the template part. When updating a template part with a data connection, the previous data connection name is searched, and if found, is removed and the data connection associated with the template is inserted. This gives the template part designer the ability to update the data connection when required to support changes made to the template part. For the template part user, this ability causes behavior that may feel counterintuitive:
In the case of inserted multiple instances of a template part with a data connection, the controls can be easily rebound after insertion. To prevent an update of a template part from changing the data connection, rename the data connection so that it is not found by the template part on update. There may be other cases where this behavior causes unexpected results. Awareness of this behavior should assist template part designers and users in identifying the cause and resolving it.
The following example demonstrates adding a data connection to a template part (please note - the third party web services availability may not be consistent); I'm also attaching a template part that you'd get by following the instructions below.
The template part now contains a data connection. To make the template part available to the form template design mode, do the following:
The template part is now part of the form template. Save and preview the form. Type MSFT in the Symbol text box and click the Refresh button (you may need to click Yes to a security dialog box). The Open text box should contain the requested data.
Richard WitteSoftware Test Engineer
MS Learning has some free Office 2007 courses. In particular, here’s a What’s New course for InfoPath. Here’s the outline:
Take a look, and let us know if you find it useful!
Folks frequently ask whether it is possible to customize the InfoPath user interface around digital signatures. Some want to show the signature at the very bottom of the form; others want to show signatures side-by-side; others want to disable form submissions when the document wasn't digitally signed. In this article, we'll look at different ways you can tweak the form design to make it happen.
Trick 1: Display signature at the bottom of the view
InfoPath lets you show digital signature UI ("click here to sign this form") under a signable section; however, this section doesn't have to include any controls! This means that you can have your signable section with controls at the top of the form, some extra content in the middle, and then another section bound to the same nodes in the data source without any controls in it.
Your design view would look like this:
Note how the signableGroup here is multiply bound; the first section has the "allow users to digitally sign this section" checkbox unchecked:
The second one has it checked, which makes the "click here to sign this form" show up; this is how the end result looks at edit-time:
Trick 2: Disallow Submit if form was not signed
InfoPath digital signatures are appended to form XML, just like form data. For example, in the form above, nodes under signature1 will store the digital signature when the user adds it:
Using this fact, we can enforce business rules in our form: for example, what if we don't want to allow form submissions for cases when form is not signed? Let's go to Tools | Submit Options and create two rules:
1) Show must-sign warning:
- condition: signatures2 node is blank (this will evaluate to true when no signature was added)
- action: show a dialog box message "you must sign the form before submitting it"
- check "stop processing rules when this rule finishes"
2) Submit to main data source:
- condition: always applies (unless the first rule fired - we wouldn't get to this execution point then)
- actions: submit to main data source + show dialog box message "submission was successful"
Trick 3: Show signatures side-by-side
Challenge: make a form that has signatures side-by-side at the bottom; additionally, person 3 should only be able to add their signature if previous signer (person 2) already signed the document.
We already know how to make the signatures appear at the bottom of view (trick 1); we also know how to determine if a signature was added to the document (trick 2). Let's put all of these tricks together into one powerful solution:
- Create 3 different signed data blocks, one for each person that will be signing the form. Second data block needs to signing a superset of data that the first one signed, etc. Your data source task pane will look like this:
- Place empty sections bound to the items that you want to sign in the columns of that table. - Use containing conditionally-formatted sections to show the signing UI only when necessary.
The resulting layout will look like this:
I'm attaching a sample form template that has this trick implemented (works in InfoPath 2003 or 2007; save the XSN to your computer before opening it).