Working with file attachments

There are a few cool things you can do with attachments, provided you are not scared of a little JavaScript.  Hopefully I have provided enough context for those of you that are not fluent in JavaScript.  If anything is unclear please comment and I will fix-up the article until it is.


As of version 8.6.4 the URL used to access attached files has changed.  The format is now "/forms/secure/org/data/<app_id>/<form_id>/attachment/<attachment_uid>.  The parts can be dynamically determined: app.getUID(), form.getId() and BO.F_Attachment.getValue().uid.  This new approach should be applied to the rest of the content in this article for any applications built using 8.6.4 or higher.  The old URL still works, but may be removed in the future.


Get Attachment File Name

You can use getValue() to retrieve the attachment object and display filename in your form.

var filename = get(BO.F_Attachment.getValue(), "fileName");

"F_Attachment" is the ID of the Attachment object that you created.  You can check out the ID from the Advanced Tab of the item properties.


Render Submitted Attachment in a later stage

1. Create an Attachment object (id = F_Attachment)

2. Create an HTMLFragment

3. Place this code in the HTML FragmentonShowevent:

var attachmentid = BO.F_Attachment.getValue().id;
var url = "/forms/secure/org/run/service/ContentStorageService/" + attachmentid;

item.setContent("<img src='" + url + "'></url>");

It is important to note that the content of an attachment cannot be displayed until the form has been submitted.  The URL here is using the REST API to get the content of the attachment, but until the form has been submitted the attachment is not available on the server.

4. When your form gets to the next stage you will now see the image rendered!  You may want to consider hiding the HTMLFragment widget until the next stage.

Provide link to attached file in a later stage (on a different page then where the attachment is)

1. Create an Attachment object (id = F_Attachment)

2. Create a Web Link object (in the Specialized palette)

3. Place this code in theonShowevent:


var attachmentid = BO.F_Attachment.getValue().id;

var url = "/forms/secure/org/run/service/ContentStorageService/" + attachmentid;

item.setDisplayValue(BO.F_Attachment.getValue().fileName);
item.setLinkValue(url);


4. When the page where the link is rendered the link display will be set to the filename and clicking on the link will open/download the file.

You can access the file name at anytime even before the form has been submitted, but you cannot create a valid link to the attachment until the form has been submitted.

Allowing Users' to Attach Multiple Attachments

You can place the Attachment item within a table.  Then I would recommend having two single line fields; one for the filename and the other for the attachment ID.  In the onItemChange event of the attachment item you can use the following JavaScript to set the field values:

BO.F_SingleLine0.setValue(BO.F_Attachment0.getValue().fileName.replace("C:\\fakepath\\", ""));
BO.F_SingleLine1.setValue(BO.F_Attachment0.getValue().id);

Change the field IDs to match those for your fields.  We also have to strip off the "C:\fakepath" that gets added by most common browsers

Now your users can attach as many files as they want and have a way of seeing what they have added. You can hide the ID column by removing it from the defined columns on the Advanced tab of the table properties.


Provide a summary of attachments and a mechanism to download

In this case we have a table of attachments from a previous stage and we want to provide a way for the user to download the attachments from a summary page in a future stage.  We can use JavaScript with the Web Link object to provide this functionality.

Place a WebLink item on your form, outside the table.  When you click on a row of the table we are going to set the link URL and display value to point to the attachment from the selected row. To do this we place the following code in the onClick event of the table:


if(item.getSelection() !== null) {
  item.getPage().F_StaticWebLink1.setLinkValue('http://<serverURL>/forms/secure/org/run/service/ContentStorageService/' + item.getSelection().F_SingleLine1.getValue());
  item.getPage().F_StaticWebLink1.setDisplayValue(item.getSelection().F_SingleLine0.getValue());
}


What this means is that if a row of the table is selected then we set the URL to the place where the attachment was stored and we set the link display value to the attachment name.  You would have to replace the IDs with those from your items.

As before this will only work if the form has already been submitted since the attachments do not exist in the Content Storage until that time.

Reading the content of an uploaded file (only if JS Security is off)

If you are running on a server that has JavaScript security turned off, a setting found in the Builder_config.properties, (which most of our client's would because their designers would be trusted), then you could use AJAX to retrieve the file that was uploaded doing something like the code below.  In my sample I placed this code in the onShow event of a multi-line text field that is visible after the form has been submitted (attachments only become available for processing after they are submitted to the server).  When the field is shown it will contain the content of the file that was previously uploaded.


var attachmentid = BO.F_Attachment.getValue().id;
var url = "/forms/secure/org/run/service/ContentStorageService/" + attachmentid;

function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    BOA.setValue(xmlhttp.responseText);
    }
  }
xmlhttp.open("GET",url,true);
xmlhttp.send();
}

loadXMLDoc(); //executes the function

Include Attachment URL in Email Sent as Submit Activity

1. Create an Attachment object (id = F_Attachment)

2. Create a Web Link (F_WebLink1)

3. Place this code in the Attachment objectonItemChangeevent:

var attachmentid = BO.F_Attachment.getValue().id;
var url = "https://<your.domain>/forms/secure/org/run/service/ContentStorageService/" + attachmentid;
BO.F_WebLink1.setValue(url);
You will have to change the "F_WebLink1" to the ID of the field where you are copying the generated URL.

4. Go to the Stages tab and click on the properties for the Submit button that is sending the email.  Click on the properties for the email, click on the Insert Item button to include the value of the F_WebLink1 field into the email.  When the email gets sent the URL will be sent as well!