dominoGuru.com

Latest Updates

Products & Applications

Showtime
My Blackberry Enterprise Server Push Utility for the Lotus Notes Client, allows you to create Jobs for individual Channel, Message, and Browser Content Pushes, as well as allows you to delete Pushed Channel Icons from defined recipient devices.

Time Tracker
The idea is simple. At the start of your day - upon completion of your first task - create an entry highlighting what you did and whether you feel it was an efficient or inefficient use of your time. Based on several requests, you can also select the priority, apply categories, or even align your time against a project.

For Lotus Notes Client v8.0 and above, you can use the Time Tracker Widget to make this process even easier!

Zephyr
My Configuration-based Rich Text Mail Merge and Emailing Utility, Zephyr allows you to create rich, data-driven emails to support automated workflow - all via Microsoft Word Mail Merge-like architecture. Dear <firstname> allows you to personalize each email message not only to the individual recipient, but also to the individual application workflow event!

xCopy
xCopy is a simple configurable xCopy client for the Lotus Notes client. By creating and defining xCopy Profiles, you can batch process your file backup or remote upload jobs. With the addition of the xCopy sidebar widget, you can easily kick-off these jobs, and modify both the xCopy Profiles and xCopy itself.

Community & Resources

Lotus Technical Information & Education Community

The Lotus Technical Information & Education community is comprised of IBM, business partner, and customer subject matter experts who use product wikis, published articles, white papers, community blogs and the latest in social media to build and share high quality technical content.

OpenNTF.org - Open Source Community for Lotus Notes Domino

OpenNTF is devoted to enabling groups of individuals all over the world to collaborate on IBM Lotus Notes/Domino applications and release them as open source.

developerWorks Lotus : Wikis

Share your deployment experiences and best practices in our wikis and help IBM to create scenarios for successful deployments. Contribute to the community by collaborating on shared content and leverage the shared knowledge from that community.

File Upload XPage Forms via OpenNTF.org Extension Library Dialogs

12/16/2011 03:12:00 AM by Chris Toohey

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!

First, let's give a quick overview of the ExtLib Dialog control.

<xe:dialog
    id="dialog1">
    <!-- Some Content Here -->
    Hello World!
</xe:dialog>

That's a rather simple ExtLib Dialog control. You define a unique ID, and place your intended content (let's say our XPage form).

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:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core"
    xmlns:xe="http://www.ibm.com/xsp/coreex">

    <xe:dialog
        id="dialog1">
        <!-- Some Content Here -->
        Hello World!
    </xe:dialog>

    <xp:button
        value="Show Dialog"
        id="button1">
        <xp:eventHandler
            event="onclick"
            submit="true"
            refreshMode="partial"
            refreshId="dialog1">
            <xp:this.action><![CDATA[#{javascript:getComponent('dialog1').show()}]]></xp:this.action>
        </xp:eventHandler>
    </xp:button>

</xp:view>

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! '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 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 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:

<xp:scriptBlock
    id="scriptBlock_fileupload_handler">
    <xp:this.value><![CDATA[var hideDialog_fileupload = function() {
    XSP.partialRefreshGet("#{id:NotesView}",
        {
            onComplete: function() {
                dijit.byId("#{id:dialog_fileupload}").hide();
            }
        }
    )
}
var refreshNotesView = function() {
    XSP.partialRefreshGet("#{id:NotesView}")
}]]></xp:this.value>
</xp:scriptBlock>

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:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core">

    <iframe
        src="#{javascript:compositeData.elementSRC}"
        id="#{javascript:compositeData.elementID}"
        class="#{javascript:compositeData.elementCLASS}">
    </iframe>

</xp:view>

The ExtLib Dialog using the cc_iframe.xsp Custom control:

<xe:dialog
    id="dialog_fileupload">
    <xc:cc_iframe
        elementSRC="/#{javascript:@WebDbName()}/fileupload.xsp"
        elementID="fileupload"
        elementCLASS="dialog fileupload">
    </xc:cc_iframe>
</xe:dialog>

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:

<xp:button
    value="Save &amp; Add More Files"
    id="button1">
    <xp:eventHandler
        event="onclick"
        submit="true"
        refreshMode="complete"
        immediate="false"
        save="true">
        <xp:this.action>
            <xp:openPage
                name="/fileupload.xsp"
                target="newDocument">
            </xp:openPage>
        </xp:this.action></xp:eventHandler>
</xp:button>

And the Save & Close button:

<xp:button
    value="Save &amp; Close"
    id="button_fileupload_submit">
    <xp:eventHandler
        event="onclick"
        submit="true"
        refreshMode="complete"
        immediate="false"
        save="true">
    <xp:this.action>
        <xp:openPage name="/hideDialog.xsp"></xp:openPage>
    </xp:this.action></xp:eventHandler>
</xp: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:

<xp:scriptBlock
    id="scriptBlock_refreshNotesView"
    value="parent.refreshNotesView()">
</xp:scriptBlock>

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:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core">

    <xp:scriptBlock
        id="closer"
        value="parent.hideDialog_fileupload()">
    </xp:scriptBlock>

</xp:view>

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.

That being said, have at it:

Dailog File Upload Controls -- Online XPage App Demo

And when you're done taking the demo for a spin, come back here and let me know what you think via the comments section below.

 
Dan SoaresName:Dan SoaresComment Great job Chris! Very clean interface and like you said, there's no reason to suspect the nested architecture :-)

Dan
Christophe SiebertName:Christophe SiebertComment Hi,
Thank you very much for this. I was banging my head against the computer screen because I couldn't figure out why my files weren't uploaded (I designed the exact same thing you mention here with extlib and dialog control).
-- Christophe
Thomas TheurerName:Thomas TheurerComment

Just found this today and try it out, but within the xe:dialog ......

<xe:dialog
    id="dialog_fileupload">
 <xc:cc_iframe
     elementSRC="/#{javascript:@WebDbName()}/fileupload.xsp"
     elementID="fileupload"
     elementCLASS="dialog fileupload">
 ></xc:cc_iframe>
 </xe:dialog>

I get the msgs in the domino designer:

Unknown property elementSRC. It is not defined on tag xc:cc_iframe.

Unknown property elementID. It is not defined on tag xc:cc_iframe.

Unknown property elementCLASS. It is not defined on tag xc:cc_iframe.

My cc_iframe:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core">

    <iframe
        src="#{javascript:compositeData.elementSRC}"
        id="#{javascript:compositeData.elementID}"
        class="#{javascript:compositeData.elementCLASS}">
    </iframe>

</xp:view>

Any ideas ?

Thomas

 

 

 

Chris TooheyName:Chris TooheyWebsite:http://www.dominoguru.comComment You'll need to add the elementSRC, elementID, and elementCLASS custom properties to the control. Check out this article for a tutorial:

Name:Comment Thx, Chris

(not published)




Evaluate this Formula: @LowerCase(@Text("FOO"))