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.

Creating Dynamic Input Custom Controls for IBM XPages with switchFacet ExtLib Controls

09/24/2012 12:51:00 PM by Chris Toohey

The Extension Library xe:switchFacet Control is quickly becoming my favorite go-to tool for Custom Control development work... but I don't think I use them in what might be considered a traditional sense.

Those of you familiar with a JavaScript Switch will immediately understand what the xe:switchFacet Control does. For everyone else (or for those of you looking for a "how a Lotus Notes developer would understand this" explanation), here's the breakdown:

Understanding the xe:switchFacet Control

At a glance, the xe:switchFacet reads like it's nothing more than a computed Subform. So let's get started by taking a look at a typical computed Subform.

For computed Subforms, a traditional Form Design Element uses some @Formula-driven logic to resolve which Subform should load at any given time.

Example Computed Subform for a Lotus Notes Domino Form Example Computed Subform for a Lotus Notes Domino Form

This Subform will use the value of the SomeField NotesItem on the Form/NotesDocument, and load the name-matched Subform. For example, if SomeField is "foo", it will load the "foo" Subform.

Where a Subform is external from the Form Design Element, the xe:switchFacet control actually uses the xp:this.facets facility to have really any control you wish as a child node of the given control. It computes which child node should be displayed at any given time based off code-driven logic.

Now let's take a look at a simple xe:switchFacet control:

<xe:switchFacet
    id="switchFacet1"
    defaultFacet="foo"
    selectedFacet="#{currentDocument.SomeField}">
    <xp:this.facets>
        <xp:div xp:key="foo">This will be foo...</xp:div>
        <xp:div xp:key="meh">This will be meh...</xp:div>
    </xp:this.facets>
</xe:switchFacet>

This xe:switchFacet uses the selectedFacet property to evaluate which "xp:key"-keyed control it should return based on the currentDocument's SomeField value.

Unlike a Subform, the xe:switchFacet allows you to define a defaultFacet, in the event there is no matching keyed control.

Now that you've seen a basic xe:switchFacet control, let's look at a JavaScript switch function example:

switch (expression) {
   case label1:
      statements1
      [break;]
   case label2:
      statements2
      [break;]
   ...
   case labelN:
      statementsN
      [break;]
   default:
      statements_def
      [break;]
}

Get the idea? The xe:switchFacet will only return the key-matched child control.

Using the xe:switchFacet Control

I love using xe:switchFacet controls in Custom Controls. The other day, I published example XPage markup using an xp:repeat control to display a custom control for "events". Here's that markup again:

<ul class="events">
    <xp:repeat
        var="thisEvent">
        <xp:this.value><![CDATA[#{javascript:var db = new Array(@DbName()[0], preferences['db_events']);
var result = @DbLookup(db,'pinlookup',key,3);
return result;}]]></xp:this.value>
        <xc:tile_event>
            <xc:this.configuration>
                <xc:configuration
                    targetID="#{thisEvent}"
                    type="list">
                </xc:configuration>
            </xc:this.configuration>
        </xc:tile_event>
    </xp:repeat>
</ul>

If you look at the xc:tile_event properties, take note of the configuration.type property. This custom control employs an xe:switchFacet control that checks the configuration.type property to load completely different content based on the property value. As mentioned in that article, I could just as well as set the configuration.type property to "minicard", thus changing what was returned at runtime.

Pretty basic, sure... but let's take this to another level. (And finally discuss the main topic of this article...)

Let's take a look at my xe:dynamic_input.xsp custom 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:switchFacet
        id="switchFacet_type"
        defaultFacet="inputText"
        selectedFacet="#{compositeData.configuration.type}">
        <xp:this.facets>

            <xp:panel
                disableOutputTag="true"
                xp:key="inputText">
                <xp:this.rendered><![CDATA[#{javascript:return (compositeData.configuration.type == "inputText") ? true : false;}]]></xp:this.rendered>
                <xp:inputText
                    id="${compositeData.configuration.controlID}"
                    value="#{currentDocument[compositeData.configuration.targetItem]}"
                    defaultValue="#{compositeData.configuration.defaultValue}"
                    multipleSeparator="#{compositeData.configuration.multipleSeparator}" />
            </xp:panel>

            <xp:panel
                disableOutputTag="true"
                xp:key="inputTextarea">
                <xp:this.rendered><![CDATA[#{javascript:return (compositeData.configuration.type == "inputTextarea") ? true : false;}]]></xp:this.rendered>
                <xp:inputTextarea
                    id="${compositeData.configuration.controlID}"
                    value="#{currentDocument[compositeData.configuration.targetItem]}"
                    defaultValue="#{compositeData.configuration.defaultValue}"
                    multipleSeparator="#{compositeData.configuration.multipleSeparator}" />
            </xp:panel>

            <xp:panel
                disableOutputTag="true"
                xp:key="inputRichText">
                <xp:this.rendered><![CDATA[#{javascript:return (compositeData.configuration.type == "inputRichText") ? true : false;}]]></xp:this.rendered>
                <xp:inputRichText
                    id="${compositeData.configuration.controlID}"
                    value="#{currentDocument[compositeData.configuration.targetItem]}"
                    defaultValue="#{compositeData.configuration.defaultValue}"
                    multipleSeparator="#{compositeData.configuration.multipleSeparator}" />
            </xp:panel>

            <xp:panel
                disableOutputTag="true"
                xp:key="comboBox">
                <xp:this.rendered><![CDATA[#{javascript:return (compositeData.configuration.type == "comboBox") ? true : false;}]]></xp:this.rendered>
                <xp:comboBox
                    id="${compositeData.configuration.controlID}"
                    defaultValue="#{compositeData.configuration.defaultValue}"
                    value="#{currentDocument[compositeData.configuration.targetItem]}">
                    <xp:selectItems
                        value="#{compositeData.configuration.selectItems}">
                    </xp:selectItems>
                </xp:comboBox>
            </xp:panel>

            <xp:panel
                disableOutputTag="true"
                xp:key="checkBoxGroup">
                <xp:this.rendered><![CDATA[#{javascript:return (compositeData.configuration.type == "checkBoxGroup") ? true : false;}]]></xp:this.rendered>
                <xp:checkBoxGroup
                    id="${compositeData.configuration.controlID}"
                    defaultValue="#{compositeData.configuration.defaultValue}"
                    value="#{currentDocument[compositeData.configuration.targetItem]}">
                    <xp:selectItems
                        value="#{compositeData.configuration.selectItems}">
                    </xp:selectItems>
                </xp:checkBoxGroup>
            </xp:panel>

            <xp:panel
                disableOutputTag="true"
                xp:key="radioGroup">
                <xp:this.rendered><![CDATA[#{javascript:return (compositeData.configuration.type == "radioGroup") ? true : false;}]]></xp:this.rendered>
                <xp:radioGroup
                    id="${compositeData.configuration.controlID}"
                    defaultValue="#{compositeData.configuration.defaultValue}"
                    value="#{currentDocument[compositeData.configuration.targetItem]}">
                    <xp:selectItems
                        value="#{compositeData.configuration.selectItems}">
                    </xp:selectItems>
                </xp:radioGroup>
            </xp:panel>

        </xp:this.facets>

    </xe:switchFacet>

</xp:view>

This control allows you to completely control which input-type control is returned to the user at runtime based completely on configuration vs. hard-coding the desired input controls into the XPage.

Want a simple xp:inputText control?

<xc:dynamic_input>
    <xc:this.configuration>
        <xc:configuration
           type="inputText"
           targetItem="title">
        </xc:configuration>
    </xc:this.configuration>
</xc:dynamic_input>

How about Rich Text?

<xc:dynamic_input>
    <xc:this.configuration>
        <xc:configuration
           type="inputRichText"
           targetItem="body">
        </xc:configuration>
    </xc:this.configuration>
</xc:dynamic_input>

What about a RadioGroup with selectItems based on an @DbLookup?!

<xc:dynamic_input>
    <xc:this.configuration>
        <xc:configuration
           targetItem="category"
           type="radioGroup"
           controlID="category">
            <xc:this.selectItems><![CDATA[#{javascript:return @DbColumn(['', ''], 'keywords', 1);}]]></xc:this.selectItems>
        </xc:configuration>
    </xc:this.configuration>
</xc:dynamic_input>

Using the xe:switchFacet to control exactly what is returned at runtime based on Custom Control properties, I could literally wire every native property for any control, and simply pass values through to the controls based on something like a Resource Bundle.

-- or a "configuration" set of NotesDocuments.

In fact, I have a scenario for a project that I'm working on that required a non-technical user to create "surveys", each "survey" with completely unique fields and potential values. While I'm not saying that this exact technique should replace your standard XPages development of creating xp:inputText controls when you need a simple xp:inputText control, I am saying that the xe:switchFacet gives us options. And options can be an amazing thing.

Online Demo

Want to give it a spin? Check out the online demo for this article here:

xe:switchFacet Custom Controls IBM XPages Demo

Conclusion

It's another code-writing-code article... but hopefully this explains why I'm loving the xe:switchFacet control lately. Aside from the demo, I'm using this control to create single-element custom controls to house any/all of my NotesDocument rendering needs.

Need this repeat to display HTML Unordered ListItems (type="list")? Need it to display larger-scale HTML DIV (type="minicard")? Need it to display the entire document in a stylized read-only context (type="fulldoc")?

And the beauty of this is that I can just as easily add another keyed control to the xe:switchFacet-driven Custom Control and change what is displayed not through source code manipulation of various XPages... but in that Resource Bundle that defines which of my Custom Control's facets should actually display.

So are you using xe:switchFacet controls? If you didn't know about them before this article, how do you think you'll use them in your future XPages development? Comment/Like/Collaborate below!

 
Dwain A WuerfelName:Dwain A WuerfelComment I didn't know about this control and like many of the controls available I find it difficult to determine how and when to best use them.  However, with XPages I do know that our limit is only limited to our imagination.  For me the issue is really just trying to get an understanding of each control.

(not published)




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