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 1 and 1 and type the answer here:
  • Post
  • Hi Scott

    The thing is that the 2nd form is not always the same.It's different every time and depends on the data in 1st form.So i think that this problem could be solved using SPQuery class from SharePoint OM.By doing so we can select what existing form to open by making the query.Could we somehow use this class in InfoPath?We should add some using directive or assembly reference?

    Thanks for your help

    Vitaly

  • Hi Vitaly,

    Yes - you can use this in your InfoPath manged code...note that you will need to develop this on your server machine.

    You will need to add a Reference to Windows SharePoint Services and then a "using" directive: using Microsoft.SharePoint;

    Once you have these in place in your managed code, you can then use the SharePoint OM.

    Scott

  • Scott, I got it working today. I still don't know what was the mistake I was doing. But the good the thing is its working now.

    Regarding the publishing once, I thought a form has to be published separately for each target site. I will give a try if I can deploy a form which was published to a Dev site into QA site. We have different server farm for different environments. For the data connections I am using UDC's, so, that is taken care of. All the forms are fully trusted, admin published forms.

    Srinivas

  • Hi Scott

    Thanks for your help but i've got another question..i've decided to make my template browser-enabled but thus some methods of Application class,such as NewFromFormTemplate disappeared..maybe i'm missing some references or what?i've added references to

    C:\Program Files\Microsoft Office\Office12\InfoPathOM\Microsoft.Office.Infopath.dll

    C:\Program Files\Microsoft Office\Office12\Microsoft.Office.InfoPath.FormControl.dll and others but still NewFromFormTemplate method and some others are not available.What should i do in order to be capable to use them?

    Thanks in advance,

    Vitaly

  • Hi Vitaly,

    As you have seen, everything that is available for designing for the InfoPath client is *not* always available for designing for the browser. This applies not only to object model differences but also controls, etc.

    The method you are asking about is an InfoPath client-only method:

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

    Scott

  • Hi Vitaly,

    As you have seen, everything that is available for designing for the InfoPath client is *not* always available for designing for the browser. This applies not only to object model differences but also controls, etc.

    The method you are asking about is an InfoPath client-only method:

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

    Scott

  • Hi Scott

    Is there any other way to open template from form?For example knowing the URL displayed when you manually create new form from template located in forms library?

    Vitaly

  • Hi Vitaly,

    If you need to create a new form from the same template, you can set the "Submit" option: Create a new, blank form - this way when your form is submitted, a new blank form will be created. And if you currently do not have a submit connection, you could create one just to "Submit to host" - won't really do anything other than cause a server postback and then create a new form. (It will obviously create a new form so all existing data is gone.)

    However, I don't believe it is possible to create a new form from a different template. In fact - as you have seen, programmatically creating a new template from the same one is not supported - nor is the Rule to create a new form (this too is not available for forms services.)

    So short of the above submit option, I don't believe there is a way to do this. (Other than maybe using your own ASPX page to host the XmlFormView control and using code behind your ASPX page to launch a new form.)

    Scott

  • Hi Scott

    It's a pity there's no simple way to do this..

    What can you say about this:i have a browser-enabled form with managed code which simply adds content of one field to another.But each time i'm clicking the button to perform this action i get this message:"An entry has been added to the Windows event log of the server".

    Log ID:5337.

    My code is just this:

    XPathNavigator xNavMain2 = this.MainDataSource.CreateNavigator();

    string string1 = xNavMain2.SelectSingleNode("//my:Comments", this.NamespaceManager).Value;

    string string2 = xNavMain2.SelectSingleNode("//my:Add_comment", this.NamespaceManager).Value;

    xNavMain2.SelectSingleNode("//my:Add_comment", this.NamespaceManager).SetValue("");

    xNavMain2.SelectSingleNode("//my:Comments", this.NamespaceManager).SetValue(string1 + "\n" + System.DateTime.Now + " " + string2);

    What should i do to get rid of this error?

    Vitaly

  • Hi Vitaly,

    You need to determine what is failing for you. This code works fine in my testing so I would suggest you either see if there is any relevant information in the Application Event log or enable Verbose logging for the various Forms Services categories, reproduce the error and then check the ULS logs on your SharePoint server to see if these point to the cause of the problem.

    Have you tried running this in the InfoPath client? Does it fail there as well?

    Scott

  • Hi Scott

    Got that problem fixed,thanks.It was security issue i think.After setting full trust mode and creating trusted certificate that code worked.

    Scott,what should we do if we want to run some code on client machine?The only available way i see is to save the form in source files and then insert javascript code in,manifest.xsf.Haven't tried it yet,though.Is it really possible?Maybe there are other more friendly ways?

    Vitaly

  • Hi Vitaly,

    As you know with a form opened in the browser, all managed code will execute on the server. I have no idea if modifying the manifest as you have described will work; however, it would not be supported.

    As you probably know you can create a custom ASPX page that hosts the XmlFormView control to display your InfoPath forms - there may be some way to get client side script to run from that ASPX page but I am not sure about that.

    Scott

  • hey,

    I'm fairly new to form services.. maybe you can shed some light on this.. I'd really appreciate that. The questions are serious :-)

    1. save to "this" sounds promising. But somehow "SaveLocation" is an unknown key in my dictionary. Now I happen to know there's a SaveLocation Property for XmlFormView. But setting that property doesn't really help. So how am I supposed to open forms carrying along this parameter? Thinking about that.. if I still have to set the parameter manually there's no gain here, is there?

    2. And as you have to publish the form template to the "Form Templates" library I cannot see how saving to "this" library actually makes sense anymore :-/ Don't you typically want to open the form from the forms library and then store filled out forms to another library?

    I'm currently looking for a way to open, save and close within a aspx site automagically. For opening purposes I use the XmlFormView control. The saving part is where I'm stuck right now. Among choosing the right library I also need a way to create unique (filled out) form names. Now() doesn't sound not really promising. Any way I can have GUIDs here?

    Again, help is much appreciated!

    Thanks in advance

  • Hi Liga,

    Let me try to address each question:

    #1: See my response to a question on January 2nd - it has modified code.

    #2: First of all, you do not actually "publish" to the Form Templates library. That is a special library that is used when you "Admin" deploy a form template. So the short answer to this is: yes - you want to determine where this form was opened from so you can dynamically determine where to submit the completed form. This is what this sample demonstrates.

    #3: Are you using a custom ASPX page for any special reason? Does the built-in FormsServer.aspx page not provide what you need? At any rate - yes, you can use a GUID to create unique names but you would need to do this in code. There are certainly other options as well:

    - Use a combination of fields from your form template

    - Use code (or a web service) to pull a unique number from a database (i.e. SQL Server)

    - Use a web service to generate and return a random number or GUID - this would eliminate the need to do this in code behind your form template

    Scott

  • Thanks for your reply, Scott :-)

    @3: Yes. Special reasons being: The form has to be shown in the context of a website. We do not want to open a new window. I already tried assigning a GUID but as it turns out Filename is a read-only property (on FileSubmitConnection). But as I'm still struggling with all the "dynamically save to library x" part I didn't really look into that yet. Any directions you can point me to?

    @2: Yes, I understand that. But still you open the form directly from that "special" library don't you? (no matter if you use formsserver.aspx or some custom.aspx site with a xmlformview control)

    So let's assume I have 10 different forms in my forms template library. Doesn't each and every one have the same "Request url"?

    It would make sense if you had a webpage in a library (let's say "NovemberForms" and within that page open a form from the forms template library and save that to novemberforms library. Much like reading the Request object in asp.

    On a side note.. are there forums I can turn to?

Page 7 of 12 (166 items) «56789»