Microsoft InfoPath 2010
The official blog of the Microsoft InfoPath team

Submitting to 'this' document library

Submitting to 'this' document library

Rate This

Have you ever needed to develop an InfoPath form template that submits back to a SharePoint document library but you did not initially know the server or library name when developing the form? Or have a scenario where your InfoPath form template could be published (or added as a content type) to multiple SharePoint document libraries and you need the submit location to be dynamic? Well read on to find out how you can do this!

When you create an InfoPath form template that needs to be able to submit to a SharePoint document library, you need to specify that connection in the initial design of the form template. However, at run time you can use managed code to determine the server and library name where the form was launched and then modify the “FolderUrl” property of the submit data connection so the form is submitted to the appropriate library.

So let’s get started setting up this sample. The C# walkthrough below uses the new InfoPath 2007 managed object model; below, you will find attached the same logic implemented in InfoPath 2003 managed object model and in InfoPath 2003 JScript.

Step 1: Create a sample InfoPath Form Template

Create a browser-compatible form template as following:

  1. Add 3 text box controls, all with a data type of text, named as follows: strFormURL, strLocation and strFolderName
  2. Add a “Submit” data connection named “Main submit”:
    • Set the document library name to a dummy SharePoint document library (i.e. http://server/dummyLib)
    • Use the concat function to concatenate the strFolderName field and _Test for the File Name property: concat(my:strFolderName, "_Test")
    • Enable the Allow overwrite if file exists property
  3. Set the Security Level of the form to Full Trust and sign the form template with a digital certificate
  4. Enable the Submit functionality (Tools | Submit Options) and choose the “Perform custom action using code” option

Now that we have the form, controls and submit functionality, let’s add the code to make this process work:

 

Step 2: Add the code

  • Click the Edit Code button on the Submit Options dialog
  • Create the following FormState Dictionary object – this will be used to store the form’s location when the form is initially opened:

private object _strUri
{
   get { return FormState["_strUri"];
  
set { FormState["_strUri"] = value; }
}

 

  • Add the following code to the Forms Loading event: 

// Get the Uri (or SaveLocation in a browser form) of where
// the form was opened.
// See if the form was opened in the browser

Boolean OpenedInBrowser = Application.Environment.IsBrowser; 

// If so, we will get the "SaveLocation" from the InputParameters

if (OpenedInBrowser)
  
_strUri = e.InputParameters["SaveLocation"].ToString();
else  

   //If it was opened in the client, we will get the Uri
  
_strUri = this.Template.Uri.ToString();

 

// Populate the fields on the form - keep in mind, this

// not necessary - this is simply to see the results

PopulateLibInfo(OpenedInBrowser);

 

  • Add the following procedure to the Forms class: 

private void PopulateLibInfo(Boolean OpenedInBrowser)

{

// Create a Navigator object for the main DOM
XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();

 

// Create Navigator objects for each field

XPathNavigator xnFormURL = xnDoc.SelectSingleNode("my:myFields/my:strFormURL", this.NamespaceManager);
XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);

XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

 

// Get the Uri stored in the FormState Dictionary variable

string strUri = _strUri.ToString();

 

// Create a variable to store the path (URL) to the document library

string strPath = "";

if (OpenedInBrowser == true) {

   //If we are open in the browser, the strUri value is just

   //the server name and library - so we just need to get

   //the URL without the last "/"

   strPath = strUri.Substring(0, strUri.LastIndexOf("/"));

} else {

   // Parse just the path to the document library -

   // this would return something like this:

   //  http://server/library

   strPath = strUri.Substring(0, strUri.IndexOf("Forms") - 1);
}


// Now, parse the URL to where the document library resides;
// this would return something like:

//    http://server or http://server/site
string strLoc = strPath.Substring(0, strPath.LastIndexOf("/"));


// Lastly, parse the URL to return just the document library name -

// in this case,we are looking for the last "/" character

// knowing that what comes after this is the document library name

string strFolder = strPath.Substring(strPath.LastIndexOf("/") + 1);

 

// Populate the fields on the form – we will use these

// values in the Submit process

xnFormURL.SetValue(strUri);

xnLocation.SetValue(strLoc);

xnFolderName.SetValue(strFolder);
}

 

  • Add the following code to the form’s Submit event:

// Create a Navigator object for the main DOM
XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();


// Create Navigator objects for the fields we will

// use to modify the FolderUrl
XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);
XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

 

// Get a reference to the submit data connection

FileSubmitConnection fc = (FileSubmitConnection)this.DataConnections["Main submit"]; 

 

// Modify the URL we want to submit to by concatenating the

// xnLocation and xnFolderName values

fc.FolderUrl = xnLocation.Value + "/" + xnFolderName.Value;

 

// Execute the submit connection

try

{

   fc.Execute();

   e.CancelableArgs.Cancel = false;

}

catch (Exception ex)

{

   e.CancelableArgs.Cancel = true;
}

 

  • Build and save the project
  • Publish and test

And that is it! You now have an InfoPath form template that will submit to whatever document library the form was opened from so you do not need to know this information when designing the template.

 

Scott Heim

Support Engineer

Attachment: submitToThisLibrary.zip
Leave a Comment
  • Please add 3 and 4 and type the answer here:
  • Post
  • Hi scorphg,

    Sorry for the delay - it has been quite busy. You would need to parse the Uri I believe but unfortunately I don't have any sample code for any of this in VB.

    If I get some time, I'll see what I can come up with.

    Scott

  • How can we populate a drop down using c# code?

    I need to set both the value and the display names and also need to read those vales and display name back.

    Right now i am only able to fill the values.

    Any suggesstions?

  • Hi neelesh,

    As you have probably seen, you do not have programmatic access to controls in InfoPath. What you would need to do is either populate a repeating structure in the main DOM that the dropdown is bound to or populate an XML resource file that is used as the source of data for the dropdown or use a web service to retrieve the data.

    Scott

  • Hello,

    This code works great for the initial submit.  But when editing an existing document I get errors.  5537   Any suggestions?  I think the URLs are different for a new document submit and an edit

    cheers,

    Brad

  • Though this query does not belong to this blog, still I am posting it here as this is a very critical requirement in one of our projects.

    Is there some way to convert the browser enabled infopath 2007 file saved in the form library to pdf/word document programmatically?

    We have a windows service which will send these converted pdf/word files as an attachment in the email.

    Thanks in advance.

  • Hi Brad,

    I was finally able to get to the issue of opening and submitting an existing form and I did need to modify the code. This updated sample code is a bit verbose but I wanted to show the various steps. Here are the updates:

    - Replace the sample Loading event code with the following:

    // See if the form was opened in the browser

               Boolean OpenedInBrowser = Application.Environment.IsBrowser;

               //Variables to store the results of testing if the form

               //being opened is new and if not, the "source" location

               //parameter so we can get the server or server/site name

               Boolean newForm = true;

               string strSource = string.Empty;

               // Get the Uri (or SaveLocation/XmlLocation in a browser form) of where

               // the form was opened.

               if (OpenedInBrowser)

                   if (this.New) //We will get the SaveLocation parameter

                       _strUri = e.InputParameters["SaveLocation"].ToString();

                   else //We will get the XmlLocation parameter

                   {

                       _strUri = e.InputParameters["XmlLocation"].ToString();

                       newForm = false;

                       //Store the "Source" parameter so we can parse this for

                       //the server/site URL

                       strSource = e.InputParameters["Source"].ToString();

                   }

               else //Opened in the client

               {

                   //See if we are opening a new form - if so, we will get the

                   //Uri to the template

                   if (this.New)

                   {

                       _strUri = this.Template.Uri.ToString();

                   }

                   else

                   {

                       //If opening an existing form, we will get the Uri

                       //of the form we are opening.

                       _strUri = this.Uri;

                       newForm = false;

                   }

               }

               // Populate the fields on the form - keep in mind, this

               // not necessary - this is simply to see the results

               PopulateLibInfo(OpenedInBrowser, newForm, strSource);

    - Replace the sample PopulateLibInfo procedure with this one:

    private void PopulateLibInfo(Boolean OpenedInBrowser, Boolean newForm, string strSourceParam)

           {

               // Create a Navigator object for the main DOM

               XPathNavigator xnDoc = this.MainDataSource.CreateNavigator();

               // Create Navigator objects for each field

               XPathNavigator xnFormURL = xnDoc.SelectSingleNode("my:myFields/my:strFormURL", this.NamespaceManager);

               XPathNavigator xnLocation = xnDoc.SelectSingleNode("my:myFields/my:strLocation", this.NamespaceManager);

               XPathNavigator xnFolderName = xnDoc.SelectSingleNode("my:myFields/my:strFolderName", this.NamespaceManager);

               // Get the Uri stored in the FormState Dictionary variable

               string strUri = _strUri.ToString();

               // Create a variable to store the path (URL) to the document library

               string strPath = "";

               if (OpenedInBrowser == true)

               {

                   if (newForm)

                   {

                       //If we are open in the browser, the strUri value is just

                       //the server name and library - so we just need to get

                       //the URL without the last "/"

                       strPath = strUri.Substring(0, strUri.LastIndexOf("/"));

                   }

                   else

                   {

                       //We need to get the server URL (up to the library name) so

                       //we can successfully submit the form.

                       string strServer = string.Empty;

                       //The following is broken into 2 parts so it is easier to see

                       //what we need to do:

                       //Get the URL up to the word "Forms" in the URL

                       strServer = strSourceParam.Substring(0, strSourceParam.IndexOf("Forms"));

                       //Get the URL up to the last "/" before "Forms" - this will be

                       //the server or server/site

                       strServer = strServer.Substring(0, strServer.LastIndexOf("/"));

                       strPath = strServer + strPath;

                   }

               }

               else //Opened in the client

               {

                   // Parse just the path to the document library -

                   // this would return something like this:

                   //  http://server/library

                   //NOTE: This process will not work when an ADMIN deployed form

                   //is opened in the client.

                   try

                   {

                       strPath = strUri.Substring(0, strUri.IndexOf("Forms") - 1);

                   }

                   catch { }

               }

               // Now, parse the URL to where the document library resides;

               // this would return something like:

               // http://server or http://server/site

               string strLoc = strPath.Substring(0, strPath.LastIndexOf("/"));

               // Lastly, parse the URL to return just the document library name -

               // in this case,we are looking for the last "/" character

               // knowing that what comes after this is the document library name

               string strFolder = strPath.Substring(strPath.LastIndexOf("/") + 1);

               // Populate the fields on the form – we will use these

               // values in the Submit process

               xnFormURL.SetValue(strUri);

               xnLocation.SetValue(strLoc);

               xnFolderName.SetValue(strFolder);

           }

    With these changes, you should be able to open and submit either a new or existing form.

    Scott

  • I was able to get this work when creating a blank template but could not get it to work using a form that is connected to a SQL DB. The error I get when opening the form from SharePoint is:

    "System.NullReferenceException

    Object reference not set to an instance of an object.

      at Template13.FormCode.PopulateLibInfo()

      at Template13.FormCode.FormEvents_OnLoad(DocReturnEvent e)

      at Microsoft.Office.Interop.InfoPath.SemiTrust._XDocumentEventSink2_SinkHelper.OnLoad(DocReturnEvent pEvent)"

    Will this solution work with a form that is created for a SQL DB? Thanks!

  • Hi derrickgh,

    Yes - this will work when your form template has been created from a database; however, the XPATH will be different for the fields you create in this sample. For instance, the strLocation node in this sample has an XPATH of: my:myFields/my:strLocation. However, when your form is created from a database connection, the XPATH is now: /dfs:myFields/my:group1/my:strLocation.

    It sounds as if you may not have the correct XPATH referenced. If you are using InfoPath 2007, simply right-click on each node that you have referenced in your code and choose Copy XPath. Then paste this into your code and compare.

    Scott

  • Thanks Scott that worked!!

    One last question. The forms I need to use this on use a search functionality, so once the form is the person finds their project in a drop-down hits search and this populates the form, which in turn clears the 3 fields used for this solution. Is there a way to run the code after the search event? Thanks again for your help

  • Hi derrickgh,

    The fields that store the folder name, location, etc. - are these in your database table as well?

    Scott

  • Scott,

    Yes, the 3 fields are in DB table.

  • Hi derrickgh,

    OK - then you can either move the code to populate these to the submit code or (the easier option) remove those fields from the database and simply add them to your datasource. Unless I am missing something from your design needs, these fields are not required to be in the database. You can display the Data Source Task Pane, right-click on the "myFields" node and choose Add. Then simply add these 3 fields. Now these will not get submitted to the database table but that should not be needed.

    Scott

  • I moved the code under the submit button and it works perfectly. Thanks again for your help!

  • Hi Scott,

    nice article.

    I have an InfoPath form created in order to be used as a workflow association form.

    I would like to retrieve the list that the workflow is (about to be) associated from the InfoPath form's FormLoad event code.

    When the association form is loaded from the web browser (through InfoPath form services), the url is "http://vmserver/development/Company1/_layouts/CstWrkflIP.aspx?List={345EB1D6-434E-4CA9-9138-823CB320AD6C}".

    How can i get this List ID?

    When using the e.InputParameters["SaveLocation"], i get the following exception "The given key was not present in the dictionary."

    How can i get the URL?

    regards

  • Hi dkarantonis,

    In this scenario, the "List" parameter is not an "InputParameter" to the form. If you debug this you will see the InputParameter count is zero. I have been unable to find a way to get this from behind the InfoPath form - so you may want to look at trying to get the URL and parsing it from the ASPX page.

    Scott

Page 5 of 12 (166 items) «34567»