Posts Tagged With: Per Henrik Lausten

Dirty pages and keeping users on them in #XPages

As I’ve mentioned before, sometimes XPages does not react the way your Notes users would expect it to react. In particular, I’ve had issues with ensuring that XPages warns the user when they try navigating away from a page that they’ve edited without first saving it. Such pages are “dirty”, since something has changed on them. Back in November we examined this in my post on Modified flags in XPages.

Unfortunately, sometimes I want to inform the user that they’re leaving a dirty page and other times I don’t. Also, sometimes, I seem to be able to add things that don’t warn the user that they’re leaving a dirty page. I’m sure there is consistency, but I haven’t figured out the rules, so I have added some code that handles these situations.

Simple warning of a dirty page

This was described in that prior post. Set the enableModifiedFlag to true and provide a couple of properties to handle it. This should fire whenever you close the XPage or navigate away via a standard link.

<xp:view xmlns:xp="" enableModifiedFlag="true">
		<![CDATA[#{javascript:if ( true ) {return "saveButton1"}}]]>
		<![CDATA[#{javascript:"Purchase order modified. Click OK to save, cancel to continue without saving"}]]>

Unfortunately, I’ve found that sometimes, it doesn’t warn me.

Warning when clicking links

I’ve got some navigation on the left side of my XPages, set up in a lovely dojo accordian with links to different parts of the application. However, not every link is set up in the same way. Some are simple and use the modifiedControl to warn users, like this one:

<xp:link text="Attachments" escape="true" id="link3" value="/att_attachmentManagement_view.xsp">

Some, however, run some scripts to remove some sessionscope variables when switching pages and I was having challenges getting the server-side Javascript to execute. So, I found a way to do both:

<xp:link text="Payment requests" escape="true" id="paymentLink" target="_self" value="#">
	<xp:eventHandler event="onclick" submit="true" refreshMode="complete">

The unfortunate thing is that when I’m using the redirect, it ignores the dirtiness of the page. Fortunately, Per Henrik Lausten found a way to deal with it on StackOverflow (thanks to PSolano), and posted it as an XSnippet on OpenNTF.

if (XSP._isDirty()){
  if (confirm ("Are you sure you want to navigate away from this page?" + "\n" + "\n" +
    "This document may contain unsaved changes." + "\n" + "\n" +
    "Press OK to continue, or Cancel to stay on the current page.")) {
    return true;
  } else {
    return false;
} else {
  return true;

So, when I added that explicitly as client-side Javascript to each eventhandler, it worked beautifully. Now, being a fan of reusable code, I wanted to put it in a CSJS script library and invoke the function all over the place. My function was as shown above, with a little wrapper:

function isClean() {
	if (XSP._isDirty()){

Then, I just needed to invoke it. My first attempt looked great to me. Call isClean() and the client side would warn the user, then stop them as appropriate.

<xp:eventHandler event="onclick" submit="true" refreshMode="complete">

Ummmm, but that didn’t work. In order to prevent the server-side Javascript from executing, the client-side Javascript needs to RETURN false, not just compute it.

<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
 <xp:this.script><![CDATA[return isClean();]]></xp:this.script>

That’s added bonus knowledge – not only are we learning how to stick to dirty pages, we’ve also learned that if you have the CSJS return a value of false, it will not execute the SSJS. I’m sure you can grasp the opportunities for validation provided there.

What about when you don’t want to warn them?

In our application, the user can select the action to perform from a combobox and then click a button to execute it. (Thanks to Scott Good, Henry Newberry and the folks at Teamwork Solutions!) The challenge here is that when the user changes the value in the combobox, the page is dirty! I mean, no data may have changed other than that combobox, but the XPage still feels dirty. Since some of those actions will result in saving the document and all of them result in navigation away from this page in an expected and managed way, we don’t want it to feel dirty. To dodge the problem, I just add a little CSJS to convince that page that it’s not really dirty.


So, then the modifiedControl is not tipped off and we execute the intended commands. Now, I’m pretty sure we don’t run into this problem with standard save buttons, but we’re in an unusual case of taking two steps to execute one action.


YMMV. These private calls to XSP methods may go away and using them requires care to ensure you’ve got the right parameters, or so the XPages Portable Command Guide advises us. Of course, everything we code may call functions that will go away and we always need to get the parameters right. So, I’m gonna use them, though sparingly.

Categories: Client-Side Javascript, Server-Side Javascript, Xpages | Tags: , , , , , , , , , , , , | Leave a comment

Filtering source views for use in #xpages

In our continuing example of purchase orders, we move from our examination of dynamic field binding in repeats to the filter used on the source view to select the competition questions we want to appear in that repeat control.

Depending on the type of competition, the source selection method and the dollar amount of the purchase order, there are different questions that the person preparing the purchase order needs to answer about the competition. There are several categories of competition questions, but the layout for the questions and answers remains the same, so I created a custom control that is used by all categories and the custom control appears on the XPage multiple times.

Each time, I pass the category as one of the properties of the custom control, as well as the criteria (type, method and amount). My view is set up with four sorted columns to filter my competition questions, so with the help of Per Henrik Lausten on StackOverflow, I learned that all I have to do is create an array to be used as the key, just as I would in LotusScript for a GetAllDocumentsByKey.

On our Purchase Order XPage, the syntax for one of the custom control insertions would appear as follows:

		sectionTitle="Competitive Process" competitionType="#{javascript:competitionType}"

When referring to the custom properties of a custom control within that control, you use compositeData followed by the property name. It makes it rather easy to pass parameters to the control.

In Java, arrays are handled by using a Vector. Simply create the Vector, then addElement to add each of my four filters (category, type, method and amount). When this is assigned to the Keys element of a dominoView used as a source, it filters the documents returned to provide only those that match our filter criteria. Here’s our filter in action:

    <xp:dominoView var="competitionQuestionView"
     viewName="CompetitionQuestions" keysExactMatch="true"
       <xp:this.keys><![CDATA[#{javascript:var vArray = new java.util.Vector();

        return vArray;

*Updated to us vArray.add instead of vArray.addElement on Jesse Gallagher’s advice. Thanks, Jesse!

Categories: Server-Side Javascript, Xpages | Tags: , , , , | 3 Comments

Blog at

%d bloggers like this: