I were off due to the incredible workload... I've started this blog entry several weeks ago. I think it's time to publish it before people forget me :)

This is a new series of articles. I'd like to introduce semi-reusable patterns that may help developers to shorten the design time for common issues.

The first article will be about "Parameter Editing".
r
Many applications use parameters, editable by power users. In classical Notes, we create a form and view; that's all, except I don't like it! Here, we will create single XPages interface as a CRUD pattern for parameters. There are two common methods for parameter editing. We will use an XPage view and a tooltip dialog for editing.

Our parameters contains a unique id (name) and some data in it.  So we have a form for the parameter:

Image:Mini-Patterns for XPages: Parameter Editing with Dialogs (1)

We may add more fields like the last modifier, author field, etc. Let's keep it simple. We will also need a view.

Image:Mini-Patterns for XPages: Parameter Editing with Dialogs (1)

Now, let's design our XPages view. I used a data table for this. Because I hate the view panel object and I'm very comfortable with data table. It's more practical.

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

     <xp:this.data>
             <xp:dominoView var="view1" viewName="Parameters"></xp:dominoView>
     </xp:this.data>

     <xp:panel style="width:500px;">
             <xp:dataTable id="dataTable1" rows="15" value="#{view1}" var="rowData">
                     <xp:this.facets>
                             <xp:pager partialRefresh="true" id="pager1" layout="FirstImage PreviousImage SeparatorPage Group NextImage LastImage" xp:key="header">        </xp:pager>
                             <xp:pager partialRefresh="true" layout="FirstImage PreviousImage SeparatorPage Group NextImage LastImage" xp:key="footer" id="pager2"></xp:pager>
                     </xp:this.facets>
                     <xp:column id="column1" style="vertical-align:top; width:150px;">
                             <xp:link escape="true" text="#{rowData.Name}" id="NameLink"></xp:link>
                             <xp:this.facets>
                                     <xp:label value="Parameter Name" id="label1" xp:key="header" style="font-weight:bold"></xp:label>
                             </xp:this.facets>
                     </xp:column>
                     <xp:column id="column2">
                             <xp:text escape="false" id="computedField2" value="#{rowData.StrValue}"></xp:text>
                             <xp:this.facets>
                                     <xp:label value="String Value" id="label2" xp:key="header" style="font-weight:bold"></xp:label>
                             </xp:this.facets>
                     </xp:column>
                     <xp:column id="column3">
                             <xp:text escape="false" id="computedField1" value="#{rowData.NumValue}"></xp:text>
                             <xp:this.facets>
                                     <xp:label value="Numeric Value" id="label3" xp:key="header" style="font-weight:bold"></xp:label>
                             </xp:this.facets>
                     </xp:column>
             </xp:dataTable>
     </xp:panel>

</xp:view>


It seems like a standard view. I placed links for the name field, we will use it. One may add/remove columns to fit the need.

Image:Mini-Patterns for XPages: Parameter Editing with Dialogs (1)

We are planning to use a tooltip dialog for CRUD operations. In order not to create duplicate form dialog, we will create a scope variable to store which document will be edited. Now, we will create a "New Parameter" button on the top. Here we will do some tricks. Dialogs coming with the extension library have a great feature. They can be launched at the server side. I mean, for a normal dialog, you may get it with "getComponent" function and use "show()" method to launch it. Extension library is creating necessary client side javascript methods to launch the dialog.

However, in tooltip dialogs, you should specify where to launch the dialog (near which element). So here is the trick:

<xp:button value="New Parameter" id="newButton"> 
       <xp:eventHandler event="onclick" submit="true" refreshMode="norefresh" onComplete="XSP.openTooltipDialog('#{id:dlg}', '#{id:newButton}')">
               <xp:this.action><![CDATA[#{javascript:viewScope.noteId="NEW";}]]></xp:this.action>
       </xp:eventHandler>
</xp:button>


It will set the required scope variable and launches the dialog at 'onComplete' part. Now, let's modify our 'NameLink' element at the data table to launch the dialog similarly.

<xp:link escape="true" text="#{rowData.Name}" id="NameLink"> 
       <xp:eventHandler event="onclick" submit="true" refreshMode="norefresh" onComplete="XSP.openTooltipDialog('#{id:dlg}', '#{id:NameLink}')">
               <xp:this.action><![CDATA[#{javascript:viewScope.noteId=rowData.getNoteID();}]]></xp:this.action>
       </xp:eventHandler>
</xp:link>


It's pretty the same. Now, it's time for the dialog. We may place it anywhere on the page. It will be hidden at first, until we launch it.

<xe:tooltipDialog id="dlg" title="Parameter"> 
       <xp:panel style="width:500.0px">
               <xp:this.data>
                       <xp:dominoDocument var="document1" formName="Parameter"
                               action="#{javascript:return viewScope.noteId=='NEW'?'createDocument':'editDocument';}" documentId="#{javascript:viewScope.noteId=='NEW'?'':viewScope.noteId}"
                               ignoreRequestParams="true">
                       </xp:dominoDocument>
               </xp:this.data>
               <xp:table style="width:100%">
                       <xp:tr>
                               <xp:td valign="top" style="width:100.0px">
                                       <xp:label value="Name *:" id="label5"></xp:label>
                               </xp:td>
                               <xp:td>
                                       <xp:inputText value="#{document1.Name}" required="true" style="width:100%">
                                               <xp:this.validators>
                                                       <xp:validateRequired message="Name is required."></xp:validateRequired>
                                               </xp:this.validators>
                                       </xp:inputText>
                               </xp:td>
                       </xp:tr>
                       <xp:tr>
                               <xp:td valign="top" style="width:auto">
                                       <xp:label value="String Value:" id="label6"></xp:label>
                               </xp:td>
                               <xp:td>
                                       
                               <xp:inputText id="inputText1" style="width:100%" value="#{document1.StrValue}"></xp:inputText></xp:td>
                       </xp:tr>
                       <xp:tr>
                               <xp:td valign="top" style="width:auto">
                                       <xp:label value="Numeric Value:" id="label4"></xp:label>
                               </xp:td>
                               <xp:td>
                                       <xe:djNumberSpinner id="djNumberSpinner1" value="#{document1.NumValue}">
                                               <xp:this.converter>
                                                       <xp:convertNumber></xp:convertNumber>
                                               </xp:this.converter>
                                       </xe:djNumberSpinner>
                               </xp:td>
                       </xp:tr>
               </xp:table>
               <xp:messages id="messages2"></xp:messages>
               <xp:panel style="text-align:right">
                       <xe:djButton id="djButton1" label="Save" disabled="#{javascript:!document1.isEditable()}">
                               <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
                                       <xp:this.action>
                                               <xp:actionGroup>
                                                       <xp:saveDocument></xp:saveDocument>
                                                       <xp:executeScript>
                                                               <xp:this.script><![CDATA[#{javascript:getComponent("dlg").hide("dataTable1")}]]></xp:this.script>
                                                       </xp:executeScript>
                                               </xp:actionGroup>
                                       </xp:this.action>
                               </xp:eventHandler>
                       </xe:djButton>
                       &#160;&#160;&#160;
                       <xe:djButton id="djButton3" label="Delete" disabled="#{javascript:document1.isNewNote()}">
                               <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
                                       <xp:this.action>
                                               <xp:actionGroup>
                                                       <xp:deleteDocument name="" message="Are you sure?"></xp:deleteDocument>
                                                       <xp:executeScript>
                                                               <xp:this.script><![CDATA[#{javascript:getComponent("dlg").hide("dataTable1");}]]></xp:this.script>
                                                       </xp:executeScript>
                                               </xp:actionGroup>
                                       </xp:this.action>
                               </xp:eventHandler>
                       </xe:djButton>
                       &#160;&#160;&#160;&#160;&#160;&#160;&#160;
                       <xe:djButton id="djButton2" label="Cancel">
                               <xp:eventHandler event="onclick" submit="true" immediate="true">
                                       <xp:this.action>
                                               <xp:actionGroup>
                                                       <xp:executeScript>
                                                               <xp:this.script><![CDATA[#{javascript:getComponent("dlg").hide()}]]></xp:this.script>
                                                       </xp:executeScript>
                                               </xp:actionGroup>
                                       </xp:this.action>
                               </xp:eventHandler>
                       </xe:djButton>
               </xp:panel>
               <xp:br></xp:br>
       </xp:panel>
</xe:tooltipDialog>


Here, there are two important points. The first is that we get the document at the launch phase of the dialog. Javascript calculates it from the viewScope.noteId parameter. You should use viewScope here. Because there are two partial refresh events in the opening of a dialog (first is setting scope, the second is document retrieval). Therefore you cannot use requestScope.

The second point is the script that closes the dialog. As I said before extension library dialogs are very cool components. You can see that we are closing them at the server side. 'hide()' function has a refresh parameter. If you give a parameter, it will refresh the element you pointed after closing the dialog.

One strange thing here; the deletion didn't work for me. I played with database, moved it to another, tried on local and finally it worked but I don't know why. I couldn't reproduce this incident again. So, let me know if you have the same problem.

You may also use a normal dialog here, if your form is larger.

That's it! You will find all screen shots and the XSP code below.

What is the next step? We have mentioned two ways for this pattern. The second pattern is using dojo grids, which will be the second post :)

Hope it helps to you.

Image:Mini-Patterns for XPages: Parameter Editing with Dialogs (1)


Image:Mini-Patterns for XPages: Parameter Editing with Dialogs (1)


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

       <xp:this.data>
               <xp:dominoView var="view1" viewName="Parameters"></xp:dominoView>
       </xp:this.data>

       <xp:panel style="width:500px;">
               
               <xp:button value="New Parameter" id="newButton">
                       <xp:eventHandler event="onclick" submit="true" refreshMode="norefresh" onComplete="XSP.openTooltipDialog('#{id:dlg}', '#{id:newButton}')">
                               <xp:this.action><![CDATA[#{javascript:viewScope.noteId="NEW";}]]></xp:this.action>
                       </xp:eventHandler>
               </xp:button>
               <xp:dataTable id="dataTable1" rows="15" value="#{view1}" var="rowData">
                       <xp:this.facets>
                               <xp:pager partialRefresh="true" id="pager1" layout="FirstImage PreviousImage SeparatorPage Group NextImage LastImage" xp:key="header">        </xp:pager>
                               <xp:pager partialRefresh="true" layout="FirstImage PreviousImage SeparatorPage Group NextImage LastImage" xp:key="footer" id="pager2"></xp:pager>
                       </xp:this.facets>
                       <xp:column id="column1" style="vertical-align:top; width:150px;">
                               <xp:link escape="true" text="#{rowData.Name}" id="NameLink">
                                       <xp:eventHandler event="onclick" submit="true" refreshMode="norefresh" onComplete="XSP.openTooltipDialog('#{id:dlg}', '#{id:NameLink}')">
                                               <xp:this.action><![CDATA[#{javascript:viewScope.noteId=rowData.getNoteID();}]]></xp:this.action>
                                       </xp:eventHandler>
                               </xp:link>
                               <xp:this.facets>
                                       <xp:label value="Parameter Name" id="label1" xp:key="header" style="font-weight:bold"></xp:label>
                               </xp:this.facets>
                       </xp:column>
                       <xp:column id="column2">
                               <xp:text escape="false" id="computedField2" value="#{rowData.StrValue}"></xp:text>
                               <xp:this.facets>
                                       <xp:label value="String Value" id="label2" xp:key="header" style="font-weight:bold"></xp:label>
                               </xp:this.facets>
                       </xp:column>
                       <xp:column id="column3">
                               <xp:text escape="false" id="computedField1" value="#{rowData.NumValue}"></xp:text>
                               <xp:this.facets>
                                       <xp:label value="Numeric Value" id="label3" xp:key="header" style="font-weight:bold"></xp:label>
                               </xp:this.facets>
                       </xp:column>
               </xp:dataTable>
       </xp:panel>

       <xe:tooltipDialog id="dlg" title="Parameter">
               <xp:panel style="width:500.0px">
                       <xp:this.data>
                               <xp:dominoDocument var="document1" formName="Parameter"
                                       action="#{javascript:return viewScope.noteId=='NEW'?'createDocument':'editDocument';}" documentId="#{javascript:viewScope.noteId=='NEW'?'':viewScope.noteId}"
                                       ignoreRequestParams="true">
                               </xp:dominoDocument>
                       </xp:this.data>
                       <xp:table style="width:100%">
                               <xp:tr>
                                       <xp:td valign="top" style="width:100.0px">
                                               <xp:label value="Name *:" id="label5"></xp:label>
                                       </xp:td>
                                       <xp:td>
                                               <xp:inputText value="#{document1.Name}" required="true" style="width:100%">
                                                       <xp:this.validators>
                                                               <xp:validateRequired message="Name is required."></xp:validateRequired>
                                                       </xp:this.validators>
                                               </xp:inputText>
                                       </xp:td>
                               </xp:tr>
                               <xp:tr>
                                       <xp:td valign="top" style="width:auto">
                                               <xp:label value="String Value:" id="label6"></xp:label>
                                       </xp:td>
                                       <xp:td>
                                               
                                       <xp:inputText id="inputText1" style="width:100%" value="#{document1.StrValue}"></xp:inputText></xp:td>
                               </xp:tr>
                               <xp:tr>
                                       <xp:td valign="top" style="width:auto">
                                               <xp:label value="Numeric Value:" id="label4"></xp:label>
                                       </xp:td>
                                       <xp:td>
                                               <xe:djNumberSpinner id="djNumberSpinner1" value="#{document1.NumValue}">
                                                       <xp:this.converter>
                                                               <xp:convertNumber></xp:convertNumber>
                                                       </xp:this.converter>
                                               </xe:djNumberSpinner>
                                       </xp:td>
                               </xp:tr>
                       </xp:table>
                       <xp:messages id="messages2"></xp:messages>
                       <xp:panel style="text-align:right">
                               <xe:djButton id="djButton1" label="Save" disabled="#{javascript:!document1.isEditable()}">
                                       <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
                                               <xp:this.action>
                                                       <xp:actionGroup>
                                                               <xp:saveDocument></xp:saveDocument>
                                                               <xp:executeScript>
                                                                       <xp:this.script><![CDATA[#{javascript:getComponent("dlg").hide("dataTable1")}]]></xp:this.script>
                                                               </xp:executeScript>
                                                       </xp:actionGroup>
                                               </xp:this.action>
                                       </xp:eventHandler>
                               </xe:djButton>
                               &#160;&#160;&#160;
                               <xe:djButton id="djButton3" label="Delete" disabled="#{javascript:document1.isNewNote()}">
                                       <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
                                               <xp:this.action>
                                                       <xp:actionGroup>
                                                               <xp:deleteDocument name="" message="Are you sure?"></xp:deleteDocument>
                                                               <xp:executeScript>
                                                                       <xp:this.script><![CDATA[#{javascript:getComponent("dlg").hide("dataTable1");}]]></xp:this.script>
                                                               </xp:executeScript>
                                                       </xp:actionGroup>
                                               </xp:this.action>
                                       </xp:eventHandler>
                               </xe:djButton>
                               &#160;&#160;&#160;&#160;&#160;&#160;&#160;
                               <xe:djButton id="djButton2" label="Cancel">
                                       <xp:eventHandler event="onclick" submit="true" immediate="true">
                                               <xp:this.action>
                                                       <xp:actionGroup>
                                                               <xp:executeScript>
                                                                       <xp:this.script><![CDATA[#{javascript:getComponent("dlg").hide()}]]></xp:this.script>
                                                               </xp:executeScript>
                                                       </xp:actionGroup>
                                               </xp:this.action>
                                       </xp:eventHandler>
                               </xe:djButton>
                       </xp:panel>
                       <xp:br></xp:br>
               </xp:panel>
       </xe:tooltipDialog>
</xp:view>

Serdar Basegmez   |   November 6 2011 09:24:00 AM   |    Development  Tips  XPages    |  
  |   Next   |   Previous

Comments (15)

Gravatar Image
Fatih Duranoğlu       05/14/2014 9:40:06 AM

Many Thanks. It works really good

Gravatar Image
Fernando Rodriguez       09/27/2013 2:58:39 PM

Hi Serrdar,

in a fresh xpage works geat !!

And then in a control too!!

Thank you very much

Gravatar Image
Serdar Basegmez    http://lotusnotus.com    09/25/2013 9:35:39 AM

It should be something else. I suggest debugging the clientside javascript and find the source of the problem. It's probably a dojo-based compatibility issue.

I don't have much experience on IE.

Gravatar Image
Fernando Rodriguez       09/25/2013 9:29:29 AM

Hello Serdar,

my server is: IBM Domino (r) Server (64 Bit) (Release 9.0 HF441 for Windows/64) and IE 9.0

I´m going to try in a new xp, I used in a control in an existing xp.

Gravatar Image
Serdar Basegmez    http://lotusnotus.com    09/25/2013 8:02:59 AM

Hello Fernando,

I tested with Domino 9 and IE7/8/9 but I couldn't reproduce the issue. What version did you test?

Gravatar Image
Fernando Rodriguez       09/24/2013 6:50:03 PM

Hi Serdar.

Very nice post. In chrome works great, but in internet explorerwhen edit the following message appears:

There was an error updating of the page. Invalid argument.

Any idea?

Thanks

Gravatar Image
Martin Rolph    http://xpages.oval.uk.com    03/23/2012 3:57:50 AM

Excellent post. Really helped me out

Gravatar Image
Don McNally    http://dmcnally.blogpsot.com    02/21/2012 8:03:41 AM

Hi, Serdar. You can disregard my issue with the Edit mode. I discovered it was an ACL problem.

I am still curious about the JavaScript code I asked about.

Thanks,

Don

Gravatar Image
Don McNally    http://dmcnally.blogpsot.com    02/20/2012 3:50:33 PM

Hi, Serdar. Thanks for this pattern. I have adapted it for date parameters as well as for multi-valued parameters of each type. The problem I see now is that I'm not sure how to get the tooltip into Edit mode for existing parameter documents. My Save button is disabled when I open an existing parameter. Any thoughts on what might be causing that?

Also, I wondered about the purpose of this code in the Save and Delete buttons: {javascript:getComponent("dlg").hide("dataTable1")}. I don't see a dataTable1 component in the dlg panel.

Thanks,

Don

Gravatar Image
Serdar Basegmez    http://www.developi.com    01/30/2012 3:03:07 AM

Thanks John!

I just found datatable more useful; however, repeat provides greater flexibility for many cases.

Gravatar Image
John Jardin    http://johnjardin.ukuvuma.co.za    01/29/2012 11:51:24 PM

Hi Sedar. Very nice post. I create this type of environment all the time.

It's interesting to note that I use a somewhat different method to achieve the same result. I tend to favor repeat controls and the ExtLib Dialog Control.

I will definitely try this out, thanks.

Gravatar Image
Jen Carey       11/14/2011 11:13:25 AM

Ditto on "This totally saved my day/week"! This really helped me, too. Thank you!!

Gravatar Image
Els       11/09/2011 6:11:47 PM

Nice! I tried to create something alike but couldn't get it to work properly, something to do with saving the changed entry. For user friendlyness i will definately try this again. I am not so happy about the way the dialogue box looks like thoug, there should be one with a glossiar look to it :)

Gravatar Image
Rami Muurimäki       11/09/2011 8:51:43 AM

This totally saved my day... week. Thanks for sharing :)

Gravatar Image
Henning Schmidt    http://www.schmhen.de    11/08/2011 2:43:37 AM

Serdar, thanks for finishing up this post. I was about to do something similar today and stumbled over your post on my daily PlanetLotus visits. Saves a couple of clockturns!

Thanks!