Monthly Archives: July 2014

WWII Veteran to speak at MWLUG

Virgil Westdale, who served in the all Japanese-American 442nd Regimental Combat Team during World War II, will be the featured speaker at MWLUG at the end of August. I’m incredibly excited because I’m not just a XPages developer, but I’m also a historian. This week, I’m actually at a conference on the invasion of southern France in WWII, and expect to hear a talk on the 442nd this afternoon.

Among the many difficult tasks that Westdale and the rest of the 442nd had in late 1944 was the rescue of the 1st Battalion of the 141st Infantry Regiment of the 36th Infantry Division. They were fighting through the Vosges Mountains in eastern France and the 442nd had been attached to the 36th. Some in the higher reaches of Allied command thought the German Army was done fighting. The Germans felt rather differently. The fighting was incredibly difficult because the Germans were experts, especially on the defensive. Those talents were compounded by the fact that they were fighting in the mountains. That battalion had advanced down a ridge line in the Vosges Mountains, but went too far. The Germans were able to slip in behind them from adjacent ridges and surround the battalion. So, the 442nd had to fight through the Germans to rescue the “Lost Battalion”.

I’ve spoken at historical conferences about the 36th Infantry Division and this fight in particular, so I expect to have a lot of questions for him. It should be outstanding!

Hat tip to Howard Greenberg of TLCC for pointing this out to me.

Categories: Conferences | Tags: , , , | Leave a comment

Showing a database in a panel in #IBMNotes

I’d never understood the whole ‘widgets’ thing that got added to Notes, where you could have additional things in that right-side set of panels. At first, I put Linked In over there, thinking I’d use it to look up people and keep track of discussions. I never did use it and eventually, it would just show me a login box, so when I changed laptops, I didn’t bother putting it back. I tried some RSS feeds, but they were far too chatty for me to ever keep track. However, I found a great use for them this past month: quick access to back-end of XPages databases.

In our environment, we put all the XPages and custom controls into one ‘design’ database and almost all of the data into another. You guessed it, the almost all is the problem. Some of the configuration documents have to reside in the design database, so it knows where the data resides. I want the users to double-click on the icon and simply open the application in XPiNC, rather than accidentally seeing the man behind the curtain. So, I put a link in the home page of our application that opens the views in Notes:

<xp:link escape="true" id="link1" text="Open Notes views" style="position: absolute;z-index:100;top:25px;left:750px;">
	<xp:this.rendered><![CDATA[#{javascript:var roles = context.getUser().getRoles();
	return @IsMember("[WFAdmin]", roles);}]]></xp:this.rendered>
	<xp:this.value><![CDATA[#{javascript:var server:NotesName = session.createName(@Subset ( @DbName(), 1));
		var filepath = database.getFilePath();
		return "Notes://" + server.getCommon() + "/" + filepath + "/TSWFKeywords?OpenView";}]]>
	</xp:this.value>
</xp:link>

That works fine, but you have to navigate back to the home page to get the the link. I could put it everywhere, but as I was looking at the Drag n Drop sidebar per a request from our newly acquired office in the UK, I figured out that creating the XML files and putting them among your widgets was really easy.

Just create a file with an XML extension — it can have any name, so I tend to create them with meaningful names, like “APPS1 Shared Resources Engage.xml” — with a format similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<webcontextConfiguration version="1.1">
<palleteItem contributeTabOnStartup="false" 
contributeToSideshelfOnStartup="true" 
hideThumbnail="false" 
id="APPS1SharedEngage" 
imageUrl="" 
providerId="com.ibm.notes.toolbox.provider.NotesViewPalleteProvider" 
singletonSidebar="false" 
title="ENGAGE SR" 
url="Notes://APPS1/Projects/Philippines/Engage/EngageSharedRes.nsf" 
viewImageUrl="">
<preferences/>
<data TYPE="DEFAULT"/>
</palleteItem>
</webcontextConfiguration>

I know five of the values that you can edit….

Line Meaning
contributeTabOnStartup=”false” If you want it to always open as a regular tab when you open Notes, set this to true. Otherwise, set this to false.
contributeToSideshelfOnStartup=”true” If you want it to always open as a panel on the right, set this to true. If you’d prefer to double-click and have it open in a new window, set this to false.
id=”APPS1SharedEngage” The unique ID for this widget. If you drag-and-drop another XML file with the same ID, it will update the existing one. When you create one using the menus, it supplies a random numeric one, but text also works, so I’d recommend that using meaningful, text ones.
title=”ENGAGE SR” This is what displays on the icon in the sidebar and on the panel header if you load it in a panel.
url=”Notes://APPS1/Projects/Philippines/Engage/EngageSharedRes.nsf” The Notes URL that you want to open. You can specify a view, but when I tried to specify an agent it didn’t execute the agent. I also tried to specify the XPage, but it never loaded. So, either the database or a specific view (with /viewname?OpenView after the filepath)

Then, drag and drop that XML file from your file system onto the My Widgets panel. In the one I have above, it always opens in a panel on startup, so I can access the views quickly and easily. However, we’re going to have 70 of these at any one time once we roll out our design to all of our projects, so I’ll probably not have any load on startup. If you don’t load them, on startup, double-clicking opens them as a new Notes window.

As soon as I finish figuring out how we’re going to configure the Drag n Drop widget, I’ll post on how to do that. While there is documentation on OpenNTF, I think I can provide some more insight and may look at doing some enhancements down the road.

Categories: Old Notes | Tags: , , | Leave a comment

Simple dialog returning a value to your #XPages

Since I’m still new to XPages, I’m always finding things that are a challenge. Most of the time, I don’t know how big a challenge they are because doing things in XPages isn’t the same as doing them in Old Notes.

Business case

On the payment request in our procurement module, the user needs to enter the exchange rate between the local currency and the base currency for approval routing. Sometimes, the payment has already been made in local currency while the exchange rate has changed. They might only know the amounts in the two currencies, but didn’t record the exchange rate at the time.

PaymentRequest

Solution

In discussions, I suggested that it might not be difficult to simply have a popup that allowed the user to enter the amounts and return the value to the payment request in the UI.

Surprisingly to me, I was right. It’s not that hard. My challenge was that I decide to put this exchange rate computer into a custom control so that I’d be able to re-use it. That meant having to figure out how to have the dialog do a partial refresh on the payment request, in order to recompute the total amount in the base currency (USD).

Existing design considerations

Our procurement module was originally designed by the brilliant minds over at Teamwork Solutions, led by Scott Good. It’s very nice, but this wasn’t included in the original requirements gathering. (What percentage of actual requirements do get into the original requirements gathering?)

Each of those line items displayed in the payment request is a separate Notes document, so, in Old Notes terms, this would be like an embedded view, but since we’re in XPages, it’s a repeat. (I am learning to love repeats!) The total payable amounts are ‘computed fields’ in XPages, which is like a computed for display field in Old Notes. As such, they wouldn’t actually save anything to the payment request document. So, we have some non-displayed computed fields with some server-side Javsacript (SSJS) that aggregates all the local amounts from those view entries and puts it into the control on the XPage. As such, when the exchange rate changes, there is a partial refresh.

So, on our exchange rate control, we had a partial refresh for onchange. Simple control, bound to a field on our payment request document.

<xp:inputText id="exchangeRate" value="#{payDoc.Exchange_Rate}" style="text-align:right;width:70.0px;">
	<xp:this.converter>
		<xp:convertNumber type="number"></xp:convertNumber>
	</xp:this.converter>
	<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="paymentCostInfoPanel">
	</xp:eventHandler>
</xp:inputText>

Design

So, I created my exchangeRateComputer custom control. I decided to make the link part of the custom control so that implementing it on any other XPage would require the least work possible.  I decided to always set the control on the XPage to be named “exchangeRate”, so I don’t have to pass a string with the control name. As an added bonus, I wanted to fill out the local currency field for the user and just let them enter the final base currency amount they’d like to see.

ExchangeRateCalculator

I ran into one problem. I couldn’t get it to do the partial refresh from the exchangeRateComputer custom control. I’d tried some XSP.partialRefreshGet commands but was having problems and realized…. I might want the name of the element to be refreshed to be different on different XPages. Since passing the compositeData value into the XSP.getElementById seemed beyond my capabilities, I decided to simply defer all refreshes to the exchangeRate control itself. So, I ended up adding an onblur partial refresh. When the user clicks on the ‘Apply to payment request button’, it puts focus onto the exchangeRate control, then, closes the dialog. Closing the dialog blurs focus from the exchangeRate control and…. with an added onblur event, performs a partial refresh for me. (The onblur event is identical to the onchange, except for the name.)

<?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">
	<xp:link escape="true" text="Compute Exchange Rate" id="computeLink" 
		style="margin-left:5px;">
		<xp:eventHandler event="onclick" submit="false">
			<xp:this.script><![CDATA[XSP.openDialog('#{id:computeDialog}');]]></xp:this.script>
		</xp:eventHandler>
	</xp:link>

	<xe:dialog id="computeDialog" title="Exchange rate calculator">
		<xp:table>
			<xp:tr>
				<xp:td>
				</xp:td>
				<xp:td>
					<xp:label id="instructions" value="Enter the amounts below to calculate an exchange rate">
					</xp:label>
				</xp:td>
			</xp:tr>
			<xp:tr>
				<xp:td style="width:150px;text-align:right;">
					<xp:label id="total_baseCurrencyLabel" value="Total Base Currency">
					</xp:label>
				</xp:td>
				<xp:td>
					<xp:inputText id="total_baseCurrency" style="width:100px;text-align:right;">
						<xp:this.converter>
							<xp:convertNumber type="number"></xp:convertNumber>
						</xp:this.converter>
						<xp:eventHandler event="onchange" submit="true"
							refreshMode="complete">
							<xp:this.action><![CDATA[#{javascript:var base = getComponent("total_baseCurrency").getValue();
var local = getComponent("total_localCurrency").getValue();
rate = local / base;
getComponent("rate").setValue(rate);}]]></xp:this.action>
						</xp:eventHandler>
					</xp:inputText>
				</xp:td>
			</xp:tr>
			<xp:tr>
				<xp:td style="text-align:right;">
					<xp:label id="total_localCurrencyLabel" value="Total Local Currency">
					</xp:label>
				</xp:td>
				<xp:td>
					<xp:inputText id="total_localCurrency"
						defaultValue="#{javascript:compositeData.localCurrency}"
						style="width:100px;text-align:right;">
						<xp:this.converter>
							<xp:convertNumber type="number"></xp:convertNumber>
						</xp:this.converter>
						<xp:this.validators>
							<xp:validateLongRange minimum="1"></xp:validateLongRange>
						</xp:this.validators>
						<xp:eventHandler event="onchange" submit="true"
							refreshMode="complete">
							<xp:this.action><![CDATA[#{javascript:var base = getComponent("total_baseCurrency").getValue();
var local = getComponent("total_localCurrency").getValue();
rate = local / base;
getComponent("rate").setValue(rate);}]]></xp:this.action>
						</xp:eventHandler>
					</xp:inputText>
				</xp:td>
			</xp:tr>
			<xp:tr>
				<xp:td style="text-align:right;">
					<xp:label id="rateLabel" value="Exchange Rate"></xp:label>
				</xp:td>
				<xp:td>
					<xp:text escape="true" id="rate"></xp:text>
				</xp:td>
			</xp:tr>
			<xp:tr>
				<xp:td>
				</xp:td>
				<xp:td>
					<xp:button value="Apply to payment request"
						id="copyButton">
						<xp:eventHandler event="onclick" submit="true"
							refreshMode="complete">
							<xp:this.script><![CDATA[var rate = XSP.getElementById("#{id:rate}"); 
XSP.getElementById("#{id:exchangeRate}").value = rate.innerHTML;
XSP.getElementById("#{id:exchangeRate}").focus();
XSP.closeDialog('#{id:computeDialog}');]]></xp:this.script>
						</xp:eventHandler>
					</xp:button>
					<xp:button value="Cancel" id="cancelButton">
						<xp:eventHandler event="onclick"
							submit="false">
							<xp:this.script><![CDATA[XSP.closeDialog('#{id:computeDialog}');]]></xp:this.script>
						</xp:eventHandler>
					</xp:button>
				</xp:td>
			</xp:tr>
		</xp:table>
	</xe:dialog>
</xp:view>

The last tweak to it is that my computed exchange rate in the dialog is just a computed field. I struggled a little until a dogpile search revealed that I needed to get that value as innerHTML. If you try getValue() on a computed field, you get bupkis, but if you grab the innerHTML, you’ve got the world in your hands.

It feels like that would be easier in Old Notes, but I hardly care any more. I have a new micro-solution in my toolbox and I expect to re-use this not only for other exchange rate computations, but to re-use the dialog and value-passing in many places. It’s all about building up your toolkit, right?

Categories: Client-Side Javascript, Old Notes, Server-Side Javascript, Xpages, XSP Functions | Tags: , , , , , , , , , , | 1 Comment

Create a free website or blog at WordPress.com.