<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>cjwalker's WebLog : InfoPath</title><link>http://blogs.msdn.com/cjwalker/archive/tags/InfoPath/default.aspx</link><description>Tags: InfoPath</description><dc:language>en-AU</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Adding a lookup dialog to an InfoPath form</title><link>http://blogs.msdn.com/cjwalker/archive/2005/05/19/420254.aspx</link><pubDate>Thu, 19 May 2005 09:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:420254</guid><dc:creator>cjwalker</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/cjwalker/comments/420254.aspx</comments><wfw:commentRss>http://blogs.msdn.com/cjwalker/commentrss.aspx?PostID=420254</wfw:commentRss><description>&lt;P&gt;A client recently experienced an issue with InfoPath where they had a repeating table containing a drop down list containing a large number of items. This worked fine for a small number of rows in the repeating table, however memory usage increased and performance degraded as more rows were added.&lt;/P&gt;
&lt;P&gt;A workaround, which actually becomes an improvement, is to add a button which launches a dialog that displays a list to select an item from. This has the benefit of not copying the drop down list contents for every row, but also provides an opportunity to enhance the lookup functionality with sorting, filtering, grouping etc.&lt;/P&gt;
&lt;P&gt;To hook it all together:&lt;/P&gt;
&lt;P&gt;1.&amp;nbsp;Create the user.htm, user.js, taskpane.htm and taskpane.js files as defined below&lt;BR&gt;2.&amp;nbsp;Add user.htm, user.js, taskpane.htm and taskpane.js as Resource files&lt;BR&gt;3.&amp;nbsp;Add a button next to the field/textbox to populate with the selected lookup value. Add an event handler to the button.&lt;BR&gt;4.&amp;nbsp;Include the functions listed below in script.js and copy the code in btnPersonLookup to your lookup button’s event handler&lt;BR&gt;5.&amp;nbsp;Set taskpane.htm as the custom task pane. Go to Tools -&amp;gt; Form Options, Advanced tab. Select taskpane.htm from the list in Task pane location.&lt;BR&gt;6.&amp;nbsp;Modify the reference to “my:Person” in selectSingleNode in btnPersonLookup – this should refer to the field or textbox that you want the selected value to go.&lt;BR&gt;7.&amp;nbsp;Give it a go.&lt;/P&gt;
&lt;P&gt;Create a lookup HTML page (this one is for selecting from a list of users): &lt;/P&gt;
&lt;P&gt;user.htm&lt;/P&gt;
&lt;P&gt;&amp;lt;html&amp;gt;&lt;BR&gt;&amp;lt;head&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;meta http-equiv="MSThemeCompatible" content="Yes" /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;title&amp;gt;Select User&amp;lt;/title&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;script src="user.js" language="JavaScript"&amp;gt;&amp;lt;/script&amp;gt;&amp;nbsp;&lt;BR&gt;&amp;lt;/head&amp;gt;&lt;BR&gt;&amp;lt;body class="dialogBody" onload="OnLoad()" onkeypress="OnKeyPress()"&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;lt;div class="section"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;lt;div id="text_instructions" class="textbox instructions"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Select a user from the list below.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;lt;div class="section"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;select class="multiLineSelect" name="selUsers" id="selUsers" size="11" onpropertychange="btnOk.disabled=(-1==this.selectedIndex)" ondblclick="SelectUser()"&amp;gt;&amp;lt;/select&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;lt;div class="buttons section"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;lt;button id="btnOk" type="submit" onclick="SelectUser()"&amp;gt;OK&amp;lt;/button&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;lt;button id="btnCancel" onclick="CloseDialog()"&amp;gt;Cancel&amp;lt;/button&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;/div&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;lt;/body&amp;gt;&lt;BR&gt;&amp;lt;/html&amp;gt;&lt;/P&gt;
&lt;P&gt;Create a Javascript file – user.js – this is referenced by user.htm&lt;/P&gt;
&lt;P&gt;user.js&lt;/P&gt;
&lt;P&gt;var L_DEFAULTUSERVALUE_Text&amp;nbsp;= "";&lt;BR&gt;var L_DEFAULTUSERNAME_Text&amp;nbsp;= "(None)";&lt;/P&gt;
&lt;P&gt;function OnLoad()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;if (window.dialogArguments)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;selUsers.innerHTML = "." + window.dialogArguments.useroptions;&lt;BR&gt;&amp;nbsp;&amp;nbsp;selUsers.outerHTML = selUsers.outerHTML;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;function SelectUser()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;if (false == btnOk.disabled)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;var oUser = selUsers[selUsers.selectedIndex];&lt;BR&gt;&amp;nbsp;&amp;nbsp;window.dialogArguments.selected&amp;nbsp;&amp;nbsp;&amp;nbsp;= true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;window.dialogArguments.selectedUserId&amp;nbsp;= oUser.value;&lt;BR&gt;&amp;nbsp;&amp;nbsp;window.dialogArguments.selectedUserName&amp;nbsp;= L_DEFAULTUSERNAME_Text != oUser.text ? oUser.text : "";&lt;BR&gt;&amp;nbsp;&amp;nbsp;CloseDialog();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;function CloseDialog()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;try&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;parent.opener = "top";&lt;BR&gt;&amp;nbsp;&amp;nbsp;parent.close();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;catch (ex)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;window.close();&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;function OnKeyPress()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;switch (event.keyCode)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;case 13: /*ENTER*/&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;SelectUser();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;case 27: /*ESC*/&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;CloseDialog();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;break;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;Create a HTML file to load as the default task pane for the form, taskpane.htm, and include this in the HEAD tags &lt;/P&gt;
&lt;P&gt;&amp;lt;script src="TaskPane.js" language="JavaScript"&amp;gt;&amp;lt;/script&amp;gt;&lt;/P&gt;
&lt;P&gt;Create another Javascript file, TaskPane.js and include the following function.&lt;/P&gt;
&lt;P&gt;function LaunchDialog(sUrl, iWidth, iHeight, oArgs)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;window.showModalDialog(sUrl, oArgs, "dialogWidth:"+iWidth+"px; dialogHeight:"+iHeight+"px; edge:Raised; center:Yes; help:No; resizable:No; status:No;");&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;Extra script.js functions&lt;/P&gt;
&lt;P&gt;function btnPersonLookup::OnClick(eventObj)&lt;BR&gt;{&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;var oArgs = new Object();&lt;BR&gt;&amp;nbsp;oArgs.XDocument&amp;nbsp;= XDocument;&lt;BR&gt;&amp;nbsp;oArgs.selected&amp;nbsp;= false;&lt;BR&gt;&amp;nbsp;var oNode = eventObj.Source;&lt;BR&gt;&amp;nbsp;var personNode;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;oArgs.useroptions = GetUserOptions('ServiceNo', 'Person_Name', oArgs.selectedUserId, true);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;XDocument.View.Window.TaskPanes.Item(0).HTMLDocument.parentWindow.LaunchDialog("user.htm", 400, 345, oArgs);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;if (true == oArgs.selected)&lt;BR&gt;&amp;nbsp;{&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;oNode.selectSingleNode('my:Person').text =&amp;nbsp; oArgs.selectedUserName;&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;var g_oXmlUsers&amp;nbsp;= null;&amp;nbsp;&lt;BR&gt;var g_sUsersOptions = "";&lt;BR&gt;var g_aOptionLookup&amp;nbsp;= new Array();&lt;/P&gt;
&lt;P&gt;var L_sSelectUser_Text = "Select user...";&lt;BR&gt;var L_sNoUser_Text = "(None)";&lt;/P&gt;
&lt;P&gt;function GetUserOptions( sUsersValueName, sUsersDisplayName, sValue, fFromDialog)&lt;BR&gt;{&lt;/P&gt;
&lt;P&gt;&amp;nbsp;if (g_oXmlUsers == null)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;try &lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//original design called a web service, but opted to load from secondary data source rather than&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//repeated calls to web service&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//g_oXmlUsers = callMethod( "GetPersonNames", "&lt;A href="http://webserver/webservice/service.asmx"&gt;http://webserver/webservice/service.asmx&lt;/A&gt;", SOAP_GETUSERS_URN, null, null, false );&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//g_oXmlUsers.ownerDocument.setProperty( "SelectionNamespaces", 'xmlns:soap="&lt;A href="http://schemas.xmlsoap.org/soap/envelope/"&gt;http://schemas.xmlsoap.org/soap/envelope/&lt;/A&gt;" xmlns:xsi="&lt;A href="http://www.w3.org/2001/XMLSchema-instance"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/A&gt;" xmlns:xsd="&lt;A href="http://www.w3.org/2001/XMLSchema"&gt;http://www.w3.org/2001/XMLSchema&lt;/A&gt;" xmlns:z="&lt;A href="http://schemas.microsoft.com/sharepoint/soap/directory/&amp;quot;'"&gt;http://schemas.microsoft.com/sharepoint/soap/directory/"'&lt;/A&gt;);&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//set the DOM object to the secondary Data Source "GetPersonNames"&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;g_oXmlUsers = XDocument.DataObjects("GetPersonNames").DOM&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;g_oXmlUsers .setProperty ('SelectionNamespaces','xmlns:dfs="&lt;A href="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution"&gt;http://schemas.microsoft.com/office/infopath/2003/dataFormSolution&lt;/A&gt;" xmlns:dsf="&lt;A href="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution&amp;quot;'"&gt;http://schemas.microsoft.com/office/infopath/2003/dataFormSolution"'&lt;/A&gt;);&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;catch (e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;g_oXmlUsers = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;if (g_sUsersOptions == "")&lt;BR&gt;&amp;nbsp;&amp;nbsp;// the XPath //Persons gets the repeating elements containing the Person Name and User ID - in our&lt;BR&gt;&amp;nbsp;&amp;nbsp;// scenario the secondary data source was a web service that returned a DataSet&lt;BR&gt;&amp;nbsp;&amp;nbsp;g_sUsersOptions = BuildOptionsList( g_oXmlUsers, "//Persons", "", sUsersValueName, sUsersDisplayName, "?");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;var sUsersOptions = '&amp;lt;option value=""&amp;gt;{0}&amp;lt;/option&amp;gt;'.replace("{0}", L_sNoUser_Text) +g_sUsersOptions;&lt;BR&gt;&amp;nbsp;sUsersOptions = sUsersOptions.replace('&amp;lt;option value="'+sValue+'"', '&amp;lt;option selected="true" value="'+sValue+'"');&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;return sUsersOptions;&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;function BuildOptionsList( xResults, xPath, sPrefix, sValueName, sDisplayName, sValue )&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;try&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;var xNodes = xResults.selectNodes( xPath );&lt;BR&gt;&amp;nbsp;&amp;nbsp;if( 0 == xNodes.length)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw( 0 );&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;var xNode;&lt;BR&gt;&amp;nbsp;&amp;nbsp;var sOptionList = "";&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;while( xNode = xNodes.nextNode() )&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;var sOptionValue&amp;nbsp;= xNode.childNodes[1].text;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;var sOptionDisplay&amp;nbsp;= xNode.childNodes[0].text;;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( sOptionDisplay )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;g_aOptionLookup[sOptionValue] = sOptionDisplay; // needed for displaying full names in errors etc., as they are not stored in the DOM!&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sOptionList += '&amp;lt;option value="' + sOptionValue + '"' + (sOptionValue == sValue ? ' selected="selected"' : '') +'&amp;gt;' + sOptionDisplay + '&amp;lt;/option&amp;gt;';&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;return( sOptionList );&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;catch( e )&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;return( "" );&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;}&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=420254" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/cjwalker/archive/tags/InfoPath/default.aspx">InfoPath</category></item><item><title>essential InfoPath tips</title><link>http://blogs.msdn.com/cjwalker/archive/2005/04/15/408479.aspx</link><pubDate>Thu, 14 Apr 2005 21:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:408479</guid><dc:creator>cjwalker</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/cjwalker/comments/408479.aspx</comments><wfw:commentRss>http://blogs.msdn.com/cjwalker/commentrss.aspx?PostID=408479</wfw:commentRss><description>&lt;P&gt;I like InfoPath, but was a bit reserved at first... and as a developer I have found InfoPath immensely frustrating at times - it takes a mind shift to really get productive with it. Given this, I thought I'd share a couple of postings I have found invaluable.&lt;/P&gt;
&lt;P&gt;The first one is for situations where you want to copy some data from the secondary (lookup) data source into the main form data source (&lt;a href="http://blogs.msdn.com/infopath/archive/2004/09/10/227972.aspx"&gt;read post here&lt;/A&gt;). The second essential piece of information was given at the bottom of the post, is that you'll more than likely need to use the current() function (as soon as you are using a Repeating Group/Section). Thankfully they also posted some tips on using the &lt;a href="http://blogs.msdn.com/infopath/archive/2004/09/13/228881.aspx"&gt;current() &lt;/A&gt;function. When editing the XPath for the Filter, setting the "secondary-data-source-ID is equal to main-data-source-ID" you need to change the main-data-source-ID to use the current() function.&lt;/P&gt;
&lt;P&gt;So in my scenario the default filter XPath looked like this: (line breaks entered to make more readable)&lt;BR&gt;&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;xdXDocument:GetDOM("References")&lt;BR&gt;/SystemArea/References/Reference/URLs/URL[../../ReferenceID = &lt;BR&gt;xdXDocument:get-DOM()&lt;BR&gt;/ns1:Question&lt;BR&gt;/my:UrlReferences&lt;BR&gt;/my:UrlReference/ns1:ReferenceID]&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Which I edited to the following:&lt;BR&gt;&lt;BR&gt;&lt;FONT face="Courier New" size=2&gt;xdXDocument:GetDOM("References")&lt;BR&gt;/SystemArea/References/Reference/URLs/URL[../../ReferenceID = current()/../ns1:ReferenceID]&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;It helps if you understand your XML schema to do this, but some trial and error might get you there.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=408479" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/cjwalker/archive/tags/InfoPath/default.aspx">InfoPath</category></item></channel></rss>