dominoGuru.com

Your Development & Design Resource

File Upload XPage Forms via OpenNTF.org Extension Library Dialogs

The OpenNTF.org Extension Library (often referred to as ExtLib) is an absolutely must-have set of controls that can be used to quickly create some pretty amazing XPage applications. There are, however, limitations -- more due to the way things work than the technology or developers contributing to the ExtLib -- that can cause confusion and in some cases downright frustration!

I ran into one of those recently with my team, as we wanted to use the ExtLib Dialog control to surface a simple File Upload form. As you can probably guess from the name, this form stores files.

Putting the contents of an XPage inside of an ExtLib Dialog control is quite frankly a rather simple thing. What is not simple however is trying to use that Dialog'ed-form to save multi-type content back to a given NotesDocument.

Note: this is a rather long article. As such, I've created anchor links to the 11 minute YouTube video walkthru of the XPage demo application and techniques discussed here, or for those of you who prefer a more hands-on approach, you can simply jump right into the Dailog File Upload Controls -- Online XPage App Demo!

You can then choose to use ServerSide JavaScript or ClientSide JavaScript to show() or hide() the Dialog control.

Here's a complete XPage that uses the Hello World! Dialog control:

The result of this is a rather small (as the Dialog sizes [by default] to the contents of the Dialog control) DHTML-style modal popup (with semi-transparent masking of the lower z-indexed background controls)... that's not really even worth showing via screencap.

'Hello World' ExtLib Dialog Control in action!

This ExtLib Dialog control will accept an entire form worth of XPage controls and pass-thru markup, allowing you to create a rather slick and certainly custom-to-the-need DHTML modal pop-up XPage form.

On submission of this XPage form -- regardless of your setting the submit button's refreshMode property to "complete" (in other words, attempting to force a "Full Update" submission of the XPage form), the form will only write back to the target NotesDocument via the HTTP GET method.

This works flawlessly for almost every type of XPage form you could want in this context. For example, you could use this technique to create a rather simple single-value changer for a datetime, input, textarea, and other text/plain-type of content. Add that to a viewPanel for some slick on-the-fly ViewEntry update operations and you've got a solution in itself.

But if, let's say, you want to add an attachment via the core XPage fileUpload control... well, that's where you'll run into problems.

The HTTP GET method can not support multipart/form-data content types. Well, at least in the realm of out of the box ExtLib Dialog controls it can't.

If you have a fileUpload control on your XPage form, and you're surfacing that form via the ExtLib Dialog control as a cool looking file upload pop-up, any text/plain content will be written correctly back to the target NotesDocument... but the would-be-attached file won't be there!

Take that exact markup, put it in it's own XPage however (sans Dialog), and it'll work perfectly.

So I started thinking about ways that we could work around this limitation, mostly because I had fallen in love with the idea of providing this sweet-looking user experience (that quite frankly just feels natural...), and it hit me: there's no reason that I have to use the out-of-the-box, textbook implementation of the ExtLib Dialog control to get the job done. I could use an HTML IFRAME element!

Here's an 11 minute, 720p walkthru of the techniques we'll discuss for the rest of this article:

See, it's all about the IFRAME!

ExtLib Dialog IFRAME wireframe

Using the IFRAME as a portal, I could just simply surface a fully-functional XPage -- in this case, fileupload.xsp -- which could handle the HTTP POST method submissions.

I'm happy to say it worked a treat... but getting it to upload a file attachment via the fileUpload control and appearing to all be part of an ExtLib Dialog control was the easy part. The hard part was getting the various interactive functions and nailing down the whole user experience so it didn't feel choppy.

While I'd like to say that it was hard work and that it took me countless hours to get it working... that couldn't be further from the truth. It turned out to be quite easy in fact.

Home.xsp XPage Process Diagram

My Home.xsp XPage would act as the default launch object. It would house my ExtLib Dialog control, a viewPanel listing all of the file attachment NotesDocuments, and a simple scriptBlock control that contained the two following ClientSide JavaScript functions:

The Dialog control would simply contain an IFRAME (actually, it contained a rather simple Custom Control that I wrote that generated a simple HTML IFRAME element). The source of that IFRAME would be the fileupload.xsp XPage.

The cc_iframe.xsp Custom control:

The ExtLib Dialog using the cc_iframe.xsp Custom control:

The fileupload.xsp XPage form (which you'll remember is not a part of the Home.xsp but is surfaced rather via the IFRAME) would need to call back to the Home.xsp ClientSide JavaScript functions to refresh the viewPanel list of all current file attachment NotesDocuments and/or initiate the ExtLib Dialog control .hide() if we were done adding attachments.

Doing that, as it turns out, is rather simple.

The parent DOM object in JavaScript will, in the context of our application, allow us to get a handle on Home.xsp from fileupload.xsp (in other words, the fileupload.xsp goes back through the IFRAME element via the parent to access the Home.xsp). Once there, all you need to do is call one of the JavaScript functions that were built via the scriptBlock control.

Now, there are two buttons on the fileupload.xsp XPage form.

The Save & Add More Files button:

And the Save & Close button:

The Save & Add More Files button simply processes the Full Update submission, and redirects the user to a new instance of the fileupload.xsp XPage form. Since this happens within the IFRAME, the user doesn't experience the browser redirect. In fact, it seamlessly brings up a new form so the user can continue adding attachments.

In fact, as an added bonus, every time the fileupload.xsp loads, it runs the refreshNotesView() JavaScript function from the Home.xsp via a simple scriptBlock control that sits above the actual content of the fileupload.xsp form:

I do this so every time I add a new file attachment NotesDocument, the viewPanel containing the list of NotesDocuments will update to reflect the latest addition.

I use this exact approach with the hideDialog.xsp XPage (which is redirected to post submission using the Save & Close button:

Yep, the dialogHide.xsp XPage's only purpose is to act as a redirect target when you're finally done adding file attachments and to call the ClientSide JavaScript function that will 1) refresh the notesPanel and when that's finished (and only when that's finished thanks to the onComplete argument) it 2) initiates the .hide() of the ExtLib Dialog control.

... and that's it really. The ExtLib Dialog control combined with the HTML IFRAME which opens a fully-functional XPage that will actually process via the HTTP POST method makes for a completely solid, dependable, and (like good CGI in a movie) completely transparent user experience. The user will never know all of the hard work and russian nesting doll-like architecture that went into giving them a rather useful little feature.

Online Demo

Want to take the demo for a spin? I only ask that you adhere to Wheaton's Law here, since Anonymous has Editor w/ Delete rights to the online demo. Also, I've told the fileUpload control to only accept image/*... so it simply won't submit if you try to put anything else in there.