InfoPath - managing lots of tooltip in your browser form

This is an idea that I've been brooding for a long time.  Finally got a prototype implemented.

 

We have a complicated looking InfoPath form.  We've always wanted to have lots of help (i) tooltips.  The picture below alone has 24 information tips.

image

 

The original plan is to use an Picture button, set the image to the image resource (so that they all share the same resource), and manually add tooltips to each button.

image

This approach works OK, but is very tedious.  Each one of our views are massive, and we have about 10 of them.  Some fields re-appear on different views and need to have the same tooltip.  This is also not very manageable - we can't modify the tooltip easily without republishing the InfoPath form.

 

An idea begin brewing by combining an external XML file along with the Rich HTML control, something that I've experimented recently.

/blog/2011/5/30/infopath-2010-embed-html-for-rich-and-web-forms.html
/blog/2011/10/12/infopath-an-example-of-using-an-xml-file-for-special-charact.html

 

Idea!

  1. Produce an XML file that has all our tooltips.
  2. Store this file in SharePoint
  3. In InfoPath, connect to this XML file as an external datasource, always load it from server
  4. Bind the XML fields to Rich HTML controls

 

1. My tooltip XML file. 

My XML file, with 2 entries in it for "office" and "state". 

Note the content of the two entries is essentially a HTML IMG tag.  With the source pointing to an image stored in SharePoint, and a tooltip.

<?xml version="1.0" encoding="utf-8"?>
<html>
  <office>
   <img xmlns="http://www.w3.org/1999/xhtml" src="/Style Library/Images/info.png" border="0" title="Select the Office that will administer this project" />
  </office>
  <state>
    <img xmlns="http://www.w3.org/1999/xhtml" src="/Style Library/Images/info.png" border="0" title="Select the State that this project will report to" />
  </state>
</html>

 

2. Store this file in SharePoint

I store this in SharePoint, on /Style Library/html-tooltip.xml.

image

 

3. Add secondary data source in InfoPath

Add XML datasource.

image

Select "Access the data from specified location"

image

Always retrieve data

image

Result data connection

image

 

4. Bind to Rich HTML controls

Switch to the secondary data source in the Fields tool pane.
Drag my new entry for "State" with the right click contextual menu.
Select Rich Text Box

image

 

There's quite a bit of clean up to do:
image

  • Remove the label
  • Set the background shade to No Fill
  • Set border to 1px solid white - you must keep 1px border, otherwise when you hover over the picture the Rich Text box will shift as InfoPath adds a focus to the box.
  • Set the height and width to 25px (size of my images).
  • Select Read-Only in the ribbon
    image
  • The result:
    image

 

Extra Note

You must show the web form Ribbon, otherwise the Rich Text is rendered differently in an iFrame, and the IMG tooltip won't show up.  Sorry, this behaviour is so weird, I do have an ugly workaround but I won't publish it - really ugly.

image

 

See it in action:

image

 

And if you need to change the text, open up the XML file in SharePoint designer, change it, and save the XML file again.

image

image

 

Summary

  • A technique to use one XML file in SharePoint to specify many HTML tooltip elements to be used within an InfoPath form
  • This allows tooltips to be updated independently of templates, and multiple elements in the InfoPath form can share and reuse the same tooltip

InfoPath - packaging site columns and content types

WARNING

I do not recommend packaging and deploying content types.  Site columns are fine, but it is best to leave InfoPath content type to SharePoint - since it does quite a few other things during self provisioning and deployment.

WARNING - you have been warned.

 

A discussion popped up on the InfoPath forums and I took a good stab at it.

http://social.technet.microsoft.com/Forums/en-US/sharepoint2010customization/thread/d2982a7c-86e1-4868-864b-2fcea68274fd/

Jason Li 

Content Deployment between different environments (InfoPath, SharePoint Designer Workflow, Content Type) in SharePoint 2010
I have read many discussions on this (or similar topic) and still would like to post this again to see if I can get real answers:

  1. I have InfoPath forms.
  2. These forms are published as content types. 
  3. I have reusable SharePoint Designer workflows.  
  4. I have document libraries created to use these content types.
  5. I have security groups.

How do I move these things from DEV to TEST, UAT all the way into PROD. 

As to #3:  GUID is driving me crazy.

 

Content Type deployment across different farms

The only way I have ever got all the environments to obey my command regarding content types is to use Solution Packages.

  1. Create InfoPath form in DEV, when publishing, use Content Type, and Site Columns.
  2. Once the Content Type and Site Columns are created, package them into a WSP.  From now on, always deploy content type and site columns using WSP.  This forces All the GUIDS to be identical across all farms, which makes everything work nice.  (see below for steps and pictures).
  3. Reusable SharePoint designer workflows can be tied to these content type / site columns, so can document library.
  4. Deploy package to TEST, you can create document libraries with feature as well, or configure them manually.  I deploy InfoPath forms to TEST by publishing from InfoPath to the TEST environment, depending on whether you are doing:
    • Site content type: publish to the destination list - it should automatically pick up the content type since the GUID are the same.  Site columns will match too.
    • Central admin forms - deploy via central admin, this places the form template back in /FormServerTemplates/ on the root site, hook this back using Content Type / advanced / form template in each list.

InfoPath forms always have data connections (since InfoPath can't do anything), you should convert all data connections to connection files hosted relatively on each DEV, TEST, etc. environment, this way you don't need to modify the form template, and depending which environment it's published to, it'll go and find the right sets of data.

 

Packaging InfoPath Content Type and Site Columns

 

Packaging site columns and content types are a lot easier now in SharePoint 2010 with VS.NET 2010. 

Grab CKS extension first.
image

  1. Create an empty SharePoint project on the DEV server.  I've always used Farm Solutions but there's probably no harm trying Sandbox Solutions.
  2. In the Server Explorer, navigate to your SharePoint DEV site.  Expand the nodes and find your Content Type under the root web.  Select Import Content Type to bring this definition into your SharePoint project.

    image
  3. This will import the content type under a feature with a default name Feature 1.  Rename the feature (VS.NET will fix all the related names).

    image
  4. Open the feature and fix the Title as well.  Notice that this feature is Web scoped.

    image
  5. Next, navigate in the Server Explorer to the site columns, and bring in the Site columns that was promoted from InfoPath.

    image
  6. This brings in two additional elements with pretty ugly GUID-names.  Need to tidy this up.

    image
  7. Open the Elements.xml file under the two site columns, and copy the <Field... /> definitions.
    Open the Elements.xml file under the InfoPath content type, and insert the site column definitions above the content type definition.

    (You'll see the content type has FieldRef to the exported columns).

    image
  8. Build the project into a package

    image
  9. Ta-da!

    image

InfoPath - an example of using an XML file for special characters

This is an old trick relating to inserting special characters (such as carriage returns) and tricking InfoPath to stop removing them! 

http://blogs.msdn.com/b/infopath/archive/2005/03/04/385577.aspx

I've decided to take some screenshots to show what you should be expecting when you apply this technique.

 

The XML file

image

 

The Data Connection

image

image

 

A formula to use it

image

The advanced Xpath is:

concat("my", xdXDocument:GetDOM("characters")/lookups/characters/@crlf, "hello", xdXDocument:GetDOM("characters")/lookups/characters/@crlf, "world")

 

Result - Rich Client

image

 

Result - Web Browser Form

image

 

The HTML generated in the browser form is:

<TEXTAREA ...>my
hello
world</TEXTAREA>

 

Notice it has the correct carriage returns creating the new lines.

 

The example XSN file if you want to download it and have some fun

https://static1.squarespace.com/static/5527bff2e4b0b430660b0d10/5527c30de4b030eeeef09715/5527c30fe4b030eeeef0a0ca/1318394572343/crlf.xsn

InfoPath - abusing a secondary datasource as temporary variable

 

This is an InfoPath technique that I've recently started using, and is pretty awesome.

Problem:

  • InfoPath is great with rules and fields, but modifying the field means that your form has now changed.  In code behind we have formstate variables, but they are not visible by InfoPath rules.
  • We may want to change these fields in later versions of the template.
  • If only we can have temporary variables to use in InfoPath

Solution in one sentence:

  • Create a secondary datasource, use abuse it to hold variables that you don't want to save to your main form

 

Real Example

How to detect if your form has been changed by the user since it was opened.  This is a tweaked version of Alec Pojidaev's How to check if your InfoPath form is “dirty”? (Tracking changes) using secondary temporary variables.

 

Steps

  1. Create a separate secondary datasource
    image
  2. Add the XML file as a secondary datasource
    image
  3. Now we have a secondary data source that we can use
    image
  4. Use that datasource to keep all the "UI" logic.  Such as:
    • "a checkbox to confirm whether I want to save and close, or just close"
    • A rich text field to show a message that I display on a separate message View
    • Various validation or toggle Booleans to control the UI
  5. Because the secondary datasource is not saved back to the main datasource, changes to the secondary datasource tree can be considered "discarded", effectively giving us "temporary variables" that rules can use.
  6. Create the form rules
    image

  7. Set the field "Form" on the secondary data source to that of the current main datasource
    image
  8. To test if the current form, at a later point in time, is the same as the form when it was opened
    image

Demo

  1. On open, is the form the same as when we opened?
    image
  2. After some changes
    image
  3. Delete our changes - "true" again
    image

 

How to use it

  1. When a form is opened, use rules (or code) to set the default values in the secondary datasource
  2. Through the lifetime of the form you can set the values to whatever you want, and use it in conditions
  3. When the form closes it doesn't get saved

Benefits

  1. You can track UI logic without actually modifying the main form
  2. You can then use the string(.) trick to save the current form on form-load, then use that value to compare with the form at a later date to see if the form had been changed by the user
  3. Some values, like "current user displayname" can be stored temporarily and is perfect for this
  4. If you didn't like a temporary variable, just remove them or rename them.  Because they are not saved to the main data source, you don't have to worry about breaking existing or future forms.

InfoPath - how to do case-insensitive text compare

Because XML is case sensitive, in InfoPath you have the problem that field may not be equal to another field during text comparison due to their case.

One way that people have been relying on is the TRANSLATE function, which requires you to write really crazy code like this:

translate( /my:fieldx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz" );

Except you usually need to do this for both sides of the equation.

 

A less well known function is actually the Microsoft extension msxsl:string-compare

http://msdn.microsoft.com/en-us/library/ms256114.aspx

Here you can use this to compare the current user's name.

msxsl:string-compare(my:a_user, xdUser:get-UserName(), "", "i") = 0

The string-compare function will return 0 based on whether the strings are identical.  The 3rd optional argument is language, using an empty string will default to system.  The 4th optional argument is case-insensitive.

The msxsl:string-compare is supported in both InfoPath 2007, 2010 and works in browser forms.

Check it out! :-)