Quantcast
Channel: XPages – Xcellerant
Viewing all 216 articles
Browse latest View live

Dojo in XPages – 25: Badge — A Cool Image Widget that’s Hard to Explain

$
0
0

In this post, I’ll demonstrate how to create the Badge widget to display image thumbnails with size animation within a tabular structure. This is a cool variation of a gallery; it displays rows of image thumbnails and automatically expands and collapses them. (It’s difficult to convey the functionality until you see an example.)

Dojo in XPages Series

Dojo in XPages — All Blog Posts

dojx.Image.Badge

The Dojo documentation says that the Badge widget loops images. That’s pretty much all it says. (The rest of the page is full of lines starting with “TODO:”.)

Maybe they couldn’t figure out how to explain it, either!

Regardless of the lack of documentation, it is very cool widget to work with images. It creates a table-like structure with image thumbnails and it expands them across multiple cells on a seemingly-random basis.

Each image starts out as a thumbnail, but one at a time expands to be double its size (taking up a 2×2 area in the layout, covering 3 other images). It then shrinks back to it’s original place and another image expands.

Here’s an example of 12 images in a 2×6 layout:

Dojo25_A

Here’s an example of the same images in a 4×3 layout:

Dojo25_B

Neither of these screen shots appear to show 12 images, but they’re there. When one image is doubled, it covers 3 other images until it shrinks back down to its original size, and then another one is increased.

This looping through the images is part of the built-in functionality of the Badge widget. This is great for providing some animation on pages that may be open for awhile, but may otherwise be static.

Here are the steps to creating your own Badge widget:

1) Include Required Resources

In order for this to work, you need to make the dojox.Image.Badge module and the Image.css stylesheet available to the page.

<xp:this.resources>
  <xp:dojoModule name="dojox.image.Badge"></xp:dojoModule>
  <xp:styleSheet href="/.ibmxspres/dojoroot/dojox/image/resources/image.css"></xp:styleSheet>
</xp:this.resources>

2) Set the Page Property to Parse Dojo on Load

Since we’ll use a declarative approach to create this widget, the page’s Trigger Dojo parse on load property must be selected (dojoParseOnLoad="true")

3) Create a Badge DIV and Images

For the Badge container, add a div with the dojoType set to dojox.image.Badge.

Define the number of rows and columns to display the images with attributes of the div.

The children property is a selector for the images to display as thumbnails and animate. It should be set to img.[className] where the classname is a class that is applied to all image tags within the div. In this example, I set them to badgeIMG in this example.

<div dojoType="dojox.image.Badge" rows="2" cols="6" children="img.badgeIMG">
  <xp:image url="/nature1.jpg" id="image13" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature2.jpg" id="image14" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature3.jpg" id="image15" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature4.jpg" id="image16" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature5.jpg" id="image17" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature6.jpg" id="image18" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature7.jpg" id="image19" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature8.jpg" id="image20" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature9.jpg" id="image21" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature10.jpg" id="image22" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature11.jpg" id="image23" styleClass="badgeIMG"></xp:image>
  <xp:image url="/nature12.jpg" id="image24" styleClass="badgeIMG"></xp:image>
</div>

This is all you need to do to set it up! Once you load the page, you should have a live Badge widget.

The next few sections cover attributes that are available for customizing the behavior.

Image Sizing

By default, the thumbnails are 50-pixel squares. If you want to change the size, you can set the cellSize attribute of the Badge div.

This example changes the thumbnail size to 150-pixel squares.

<div dojoType="dojox.image.Badge" rows="2" cols="6" children="img.badgeIMG" cellSize="150">

Dojo25_C

Transition Delay

Another attribute you can change is the delay between resizing images. The default seems to be 2.5-3 seconds, but you can change that with the delay attribute, where you define the value in milliseconds. To extend the delay to 5 seconds, set the delay to 5000.

<div dojoType="dojox.image.Badge" rows="2" cols="6" children="img.badgeIMG" delay="5000">

If you want to annoy your users, set it to 100.

Adding Threads

The thread count is the number of images that are enlarged at a time. The default is 1, but you can increase this with the thread attribute. This can be a cool effect with a larger data set (especially because they don’t all animate at the same time — their timing is offset), but use it wisely; images will often overlap if there are too many threads. Even 3 is too many for my set of 12 images.

Dojo25_D

If you really want to annoy your users, increase the thread count while also drastically decreasing the delay.

More Examples

This Dojo demo page has additional examples of this in use.

Interestingly, if you look at the example in the upper right hand corner of the page, it looks like you can create the same effect with a bunch of div tags, rather than images.



Article Published in The VIEW: Getting Started with XPages Localization

$
0
0

Kathy Brown and I co-wrote and article on getting started with XPages Localization for The VIEW journal (subscription required).

Abstract

The enterprise is global. If your organization stretches across borders or your clients are in other countries, you cannot just develop an application in your native language and expect that to be good enough. XPages allows you to enable localization and provide multiple languages to display to users.

Here in Part 1 of this two-part series, we will discuss localization features built into XPages. We’ll also demonstrate how to enable localization, work with the localization files, and verify that the application is handling localization. Additionally, we provide some helpful tips to make the process easier. In Part 2, we will demonstrate how to extend out-of-the-box functionality by providing a means to translate computed values and other programmatic text.


Dojo in XPages – 26: Combining Badge with LightboxNano

$
0
0

In the last two posts, I showed how to implement a Badge to display a set of thumbnail images with some animation as well as the LightboxNano widget to display an image in a specialized dialog. In this post, I’ll show how to combine the two so you can create the badge and add the ability to click on any thumbnail to see the full-sized image in a dialog when clicked.

Dojo in XPages Series

Dojo in XPages — All Blog Posts

Sample Widget

The effect that we’re going for is to have the badge to display the set of thumbnail images and animate them, but have the ability to see any of the thumbnails full-sized.

Dojo_26_A

The source also shows a variation on how to define a LightboxNano widget declaratively, rather than programmatically, as shown in a previous post.

1) Include Required Resources

We’ll need to include two dojo modules (dojox.Image.Badge and dojox.Image.LightboxNano) and the image.css stylesheet on the page.

<xp:this.resources>
  <xp:dojoModule name="dojox.image.Badge"></xp:dojoModule>
  <xp:dojoModule name="dojox.image.LightboxNano"></xp:dojoModule>
  <xp:styleSheet href="/.ibmxspres/dojoroot/dojox/image/resources/image.css"></xp:styleSheet>
</xp:this.resources>

2) Set the Page Property to Parse Dojo on Load

Since we’ll use a declarative approach to create both the badge and the lightbox nano widgets, the page’s Trigger Dojo parse on load property must be selected (dojoParseOnLoad="true")

3) Create a Badge DIV and add LightboxNano Images

For the Badge container, add a div with the dojoType set to dojox.image.Badge.

Define the number of rows and columns to display the images with attributes of the div.

The main difference between this and the example in the last post is that we use a tags around each xp:image tag to set up the LightboxNano for each image. The xp:imagetags populate the badge and the a tags open the images in the LightboxNano dialog. (In this example, they are all using images included within the application as image resources.)

If you have separate thumbnail and full-sized images, you should use the thumbnails within the xp:image tags and the full-sized images on the a tag.

<div dojoType="dojox.image.Badge" rows="2" cols="6" cellSize="100" children="img.badgeIMG">

  <a data-dojo-type="dojox.image.LightboxNano" href="nature1.jpg">
    <xp:image url="/nature1.jpg" id="image13" styleClass="badgeIMG"></xp:image>
  </a>
  <a data-dojo-type="dojox.image.LightboxNano" href="nature2.jpg">
    <xp:image url="/nature2.jpg" id="image1" styleClass="badgeIMG"></xp:image>
  </a>
  <a data-dojo-type="dojox.image.LightboxNano" href="nature3.jpg">
    <xp:image url="/nature3.jpg" id="image2" styleClass="badgeIMG"></xp:image>
  </a>

  <!-- Code for 9 additional images in this example left out -->

</div>

Take a look at the previous post on the Badge widget for more information on customizing the badge thumbnail gallery display (size, speed, layout, and timing).


The Differences Between The resource and resources Tags in an XPages Theme

$
0
0

If you’ve modified a theme, you’ve almost certainly used resource tags to include stylesheets and client-side JavaScript libraries. Each resource tag specifies a single resource to include. However, you can also use the resources tag to include multiple resources. In this post, I’ll explain the differences and a caveat.

resource Tags

Most themes only make use of resource tags because they’re what’s demonstrated by the examples. When you create a new theme, these comments are included by default:

<theme extends="webstandard" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="platform:/plugin/com.ibm.designer.domino.stylekits/schema/stylekit.xsd" >
  <!-- 
    Use this pattern to include resources (such as style sheets
    and JavaScript files that are used by this theme.
  -->
  <!--
    <resource>
      <content-type>text/css</content-type>
      <href>mystylesheet.css</href>
    </resource>
  -->

If I have a stylesheet named myStylesheet.css, it’s very easy to tweak that example to include it in my theme.

<resource>
  <content-type>text/css</content-type>
  <href>myStylesheet.css</href>
</resource>

I can also include a client-side JavaScript library like this:

<resource>
  <content-type>application/x-javascript</content-type>
  <href>csjsMyClientJSLibrary.js</href>
</resource>

Each resource tag defines a single resource. It has child tags to define the content type and the path to the resource.

The resources Tag

The resource tags work well, but you can also use a single resources tag instead and there are a few reasons that this is advantageous.

If you’ve looked in the source of an XPage or custom control where you included one or more resources, you’ve noticed that there’s a this.resources tag that includes a line for each individual resource.

For example, in a test database, I created an SSJS script library and a stylesheet and included them as resources on an XPage. This is how they are included in the page source within an xp:this.resources tag:

<xp:this.resources>
  <xp:script src="/ssjsMyLibrary.jss" clientSide="false"></xp:script>
  <xp:styleSheet href="/myStylesheet.css"></xp:styleSheet>
</xp:this.resources>

With the resources tag, you can use a similar syntax in the theme.

There are a few benefits:

1) Succinct syntax

Especially as the theme grows to include a lot of resources, it is nicer to have a less verbose syntax so you can review the contents of the theme more easily.

All of the same properties are available as with the resource tag, they’re just specified as attributes rather than as child tags.

2) Ability to include server-side resources

The resource tag can only include client-side resource (client-side JavaScript libraries, stylesheets, dojo modules,etc), but the resources tag can include SSJS libraries and resource bundles as well.

This makes it much easier to deploy those resources application-wide.

Tip for Specifying Resources in the Theme

There isn’t a simple way to add resources to the theme, but here’s how to streamline the process:

  1. Add the resources to an XPage or custom control
  2. View the source of the page and copy the block to the theme (and remove it from the page)
  3. Remove xp: and xp:this. from the tags
<resources>
  <script src="/ssjsMyLibrary.jss" clientSide="false"></script>
  <styleSheet href="/myStylesheet.css"></styleSheet>
</resources>

This works, but it’s a good idea to specify the type attribute (for example type=”text/javascript”) as well.

Caveat – Avialability of SSJS Library on Page Events

There is an important caveat to loading SSJS libraries this way. The theme is loaded during the Render Response phase of the JSF lifecycle, so SSJS libraries loaded by the theme will not be available to page events that happen before that phase. Therefore, if you need to execute library functions on page-level events that happen earlier (beforePageLoad and afterPageLoad), you will need to include them on the page and not in the theme. SSJS libraries loaded by the theme are available to the beforeRenderResponse and afterRenderResponse events.


Book Review – Mastering XPages, Second Edition

$
0
0

I recently completed reading Mastering XPages, Second Edition. I read the previous edition cover to cover and did the same for this edition — it reinforced my understanding of a many topics, corrected my understanding of a few topics and opened my eyes to some features I had not yet tried. In short, this extremely thorough reference covers everything from <a> links to z-index; it is a worthy successor to the original book and a valuable addition to any Notes developer’s library.

I love giant tech books, so this 1000+ page tome makes me hearken back to the days of plowing through several large volumes (in addition to the yellow books!) to learn everything I could about earlier versions of Notes and Domino. In recent years, lots of great information has been disseminated in smaller chunks via blogs and articles, but XPages as a platform is so broad that there is absolutely a place for such an in-depth authoritative reference.

Mastering XPages starts at the beginning, dipping its toes in the water with the history and foundation of XPages. It progressively builds from explaining the basics the Notes schema and JSF through to simple actions and programming, then wading into deeper waters of partial refreshes and mixing client- and server-side code, before diving into the deep end of advance performance tuning.

Even though XPages has only been around for 5 years, it was interesting to review the history and gain a renewed sense of appreciation of how far the platform has come in just a few years. (Remember the days of creating, saving, then cleaning up temporary documents just to exchange information with LotusScript agents?)

Why Read the Second Edition if You’ve already Read the First Edition?

Even if you’ve read the first edition, it is worthwhile to read the second edition, for several reasons:

  1. It is updated for Notes 8.5.3 and 9.x, with numerous tips and descriptions of new and updated properties and features, including the Extension Library that is now built into core Notes. (Examples include Data Views and mobile development design patterns and enhancements, including the new DeviceBean and touch-based events.)
  2. It contains several new chapters (and additional information in existing chapters), including mobile controls and tons of great information about performance and scalability.
  3. If you’ve been working with XPages for awhile since you read the first edition, you’ll find that your additional experience provides a stronger foundation to get more out of the book. Several years after reading the first book, I can much more easily grasp the more complicated topics.

Writing Style

Even though it’s a massive book, the writing style is fairly colloquial, making it easier to read than you might expect.

There’s a reminder not to execute admin commands on a production server ‘willy nilly’ and a demo of customizing a pager to spoof the Goooogle results pager with “Loooootus”. Bonus points for referring to the use of $$Return fields as a “black magic” practice!

It definitely does not read like a stuffy manual; the authors clearly explain topics from the most basic (view panels) to the inkhorn (advanced performance analysis and tuning).

GoFaster=1

Okay — it’s not quite that simple, but the new chapters on performance tuning are well worth the price of the book alone. Two new chapters dive deep into the bowels of the JSF lifecycle and heap dumps to provide critical information about application performance and scalability. Many other tips throughout the book also show how to build performant applications by efficient use of partial refreshes and partial execution, as well as XPiNC enhancements to optimize initial load time and the use of applications with a shared design.

Things I Learned

Even after working with XPages heavily for the past 4-5 years, there are a myriad of features that I either learned about or gained a better understanding of as a result of reading this book.

It was a refresher on features that I was aware of but rarely use:

  • navigation rules
  • the ability to assign access control to a panel
  • the In Place Form control
  • mask converters
  • the createForm property of an XPage
  • control declaration snippets
  • the requestParamPrefix property of a document data source
  • the generic viewEntry object that you can use to get the current view entry (based on the context) just like currentDocument gets the closest document data source
  • the ability to programmatically get/set the custom properties of a different custom control from outside of that custom control
  • the ability (since 8.5.3) to use sortColumn and search properties of a view data source together (and the fact that column sorting icons are no longer disabled post-8.5.2 after a search was executed because now search and sort can work together)

I learned about some features that I wasn’t aware of:

  • making Dynamic Content facets available to web crawlers
  • the skipContainers property of a radio button
  • the fact that IE11 does not work with the version of CKEditor in 9.0.1

I also learned more about a new feature that I’m well aware of but haven’t tested even though I complained for a long time that it was desperately needed:

  • *cough* the SSJS debugger *cough*

There are many great debugging tips for XPiNC, SSJS, Java, Client-JavaScript, as well as information on how to debug when you find the compressed and aggregated libraries hard to troubleshoot.

And there’s plenty more where that came from. If you don’t know all of this already, it will be well worth your time to read this book. I still refer to the original Mastering XPages book from time to time and I’m sure I will refer to this edition numerous times in the future.


Dojo in XPages – Demo Site

$
0
0

Due to David Leedy’s generosity, I now have a simple demo application set up at demo.xcellerant.net. Currently, there are samples of several Dojo widgets about which I’ve recently blogged and I will add to it over time.

Each page has a sample that corresponds with one blog post, along with a button to link to the blog post in order to learn more about it and get the code.

DemoSite

Dojo in XPages Series

Dojo in XPages — All Blog Posts


Article Published in The VIEW: Extending Localization in XPages

$
0
0

The second part of a 2-part series on localization that Kathy Brown and I co-wrote has been published in The VIEW journal (subscription required). Part 1 showed how to get started with XPages Localization and part 2 shows how to extend XPages localization to handle things that the built-in localization functionality does not handle.

Abstract

The enterprise is global; business doesn’t only happen in your native language. It is not practical to expect everyone to speak the same language to use your applications.

The first article in this series showed how to enable localization and use the built-in features of XPages to set up translations for all hard-coded values. Part 1 demonstrated a few features that browsers handle for you automatically and explained how to enable and use the built-in features of XPages.

When you started developing in XPages, you likely saw the blue diamond next to virtually every property to compute it. Unfortunately, built-in localization features do not handle those computed values. This article shows how to enhance localization and provides additional tips and tricks for localization support.


XPages Tip: Accessing a custom control’s custom property from outside of the custom control

$
0
0

If you’ve used custom properties, then you’re aware that the compositeData object provides access to those properties within the custom control. However, you can also access those properties from outside of the custom control. In this post, I’ll show how.

Accessing a Custom Property from Within a Custom Control

Let’s start with a custom control named myCC that has a custom property named myProperty. Here’s what it looks like to include it on an XPage and pass in a value of myValue:

<xc:myCC myProperty="myValue"></xc:myCC>

On the custom control, you can refer to that value as compositeData.myProperty. Here’s an example of a computed field that displays the property value.

<xp:text escape="true" id="computedField1" 
  value="#{javascript:return compositeData.myProperty;}">
</xp:text>

Accessing a Custom Property from Outside of a Custom Control

If you have a need to access the a value passed to a custom property of a custom control from outside if the custom control, there are two steps to take:

  1. Add an id to the custom control instance on the page (so you can refer to it)
  2. Get the custom control component, retrieve a map of its property values, and then access the property that you need

Here’s an updated example of the custom control implementation on the XPage, with an id attribute added.

<xc:myCC myProperty="myValue" id="ccID"></xc:myCC>

Here’s how to refer to the custom property from the XPage:

getComponent('ccID').getPropertyMap().getProperty('myProperty');

This concept will work fine with multiple instances of the same custom control within a page because each instance would be required to have its own unique ID.

If you want to make the property available in client-side Javascript, you can use the "#{javascript: }" syntax:

var propertyValue = "#{javascript:getComponent('ccID').getPropertyMap().getProperty('myProperty')";

A Use Case

Here’s an example where I’ve recently found this useful. I have an application where I have a flexible grid custom control that takes a parameter with the URL for a REST service to supply the data. When I execute a search, I don’t want to reload the entire page — I just want to call the REST service to get the updated results and apply them to the grid.

But the search field exists as part of the application layout, so it’s outside of the grid custom control. Since the grid control is used for several types of grids, the REST service will vary, so I need to read a custom property of the custom control from another place on the page. This allows the Search feature to be reusable like the custom control.



Order of execution for client-side JavaScript event handlers and callbacks

$
0
0

There are a number of different places from which you can execute client-side JavaScript upon clicking an xp:button. In this post, I’ll document both the order of execution and which ones execute for each refreshMode option.

Client-Side Javascript Events and Callbacks

There are 5 ways that I can see to execute client-side JavaScript when a button is clicked.

The easiest way is the “Client” event tab. Use the script editor to add code.

There are also 3 callbacks on the event handler (onStart, onComplete, onError) where you can add client-side JavaScript. These are a little harder to get to — you have to switch to the Source view, click on the xp:eventHandler tag, and then find them in All Properties under the events category.

EventCallbacks

You can also run client-side JavaScript from an SSJS code using the view.postScript() method. (Here’s an example snippet from Russ Maher) This is a bit more complex because you need to get code into a string (watch the quotes closely!), but it works well.

Here’s an example:

view.postScript('alert("server event - view.postScript");');

An Example

Here’s an example of a button that makes use of all 5 options. xp:this.script is the client-side event. xp:this.action is the SSJS event code with the view.postScript call. onComplete, onError, and onStart are part of the xp:eventHandler itself.

<xp:button value="Refresh Fields 2-4" id="button2">
  <xp:eventHandler event="onclick" submit="true"
    onComplete="alert('server event callback - oncomplete');"
    onError="alert('server event callback - onerror');"
    onStart="alert('server event callback - onstart');"
    refreshMode="partial" refreshId="field1">

    <xp:this.script>
      <![CDATA[alert('client event');]]>
    </xp:this.script>

    <xp:this.action>
      <![CDATA[#{javascript:view.postScript('alert("server event - view.postScript");');}]]>
    </xp:this.action>
  </xp:eventHandler>
</xp:button>

Order of Execution

The callbacks that run very based on the refreshMode property of the event.

If the page is fully refreshed, then none of the event handler callbacks are triggered. If the event is set to No Update or No Submission, then view.postScript will not run.

Here is the order of execution for each event and callback (with the exception of onError, because it would break the flow) that runs, based on the refreshMode:

  • Full Refresh — client event, view.postScript
  • Partial — client event, onstart, view.postscript, oncomplete
  • No Update — client event, onstart, oncomplete
  • No Submission — client event

The only way they all run is with a partial refresh.

Generated Code in the Browser

Here’s what gets generated and passed to the browser for our sample button (when set to partial refresh). The client-event code is defined in its own function. In the XSP.attachPartial() call, the client side event handler function and the callback functions are all passed (along with the button ID, refresh target ID, etc)

<script type="text/javascript">

function view__id1__id13_clientSide_onclick(thisEvent) {
alert('client event');
}

XSP.addOnLoad(function() {
XSP.attachPartial("view:_id1:_id13", "view:_id1:button2", null, "onclick", view__id1__id13_clientSide_onclick, 2, "view:_id1:field11", "alert(\'server event callback - 

onstart\');", "alert(\'server event callback - oncomplete\')", "alert(\'server event callback - onerror\')");
});

</script>

The Client-Side Javascript Event vs the onStart Callback

Of particular interest to me is the distinction between the onStart callback of a server side event and the client-side JavaScript event.

I like the concept of the onStart callback, because your code can be consistent if you’re also running code onComplete, however, the client-side JS event is easier to get to and it also has the ability to return false and cancel execution of the server-side event. (The onStart callback throws an error if you try to return false, because it’s not a function.)

If you have any other insight into the differences or a benefit to using the onStart callback of the event handler, I’d love to hear it.


Providing URL Parameters for Multiple Document Data Sources

$
0
0

You’re no doubt used to seeing URLs to open a document that look like this: http://www.server.com/db.nsf/myPage.xsp?action=openDocument&documentId=0123456789ABCDEF0123456789ABCDEF in XPages. The documentId and action URL parameters are used by each document data source by default. In this post, I’ll show how you can use the requestParamPrefix property to define a separate set of URL parameters for an additional data source.

By default, a document data source will use the documentId and action parameters to determine the document to open and the edit mode. However, if you have more than one document data source on a page, this may not be the behavior that you want.

For example, I have a database with a simple XPage that has two document data sources for the Person form.

<xp:dominoDocument var="document1" formName="Person"
  action="openDocument">
</xp:dominoDocument>
		
<xp:dominoDocument var="document2" formName="Person"
  action="openDocument">
</xp:dominoDocument>

If I open the page with a standard URL, both display the same document.

http://www.server.com/db.nsf/TwoDataSources.xsp?documentId=9E9324F079A7F31885257D06007ADF9C&action=openDocument

requestParamPrefix_1_SameDocument

If I change the action parameter to editDocument, then both change to edit mode. Sounds like a great way to generate a save conflict!

ignoreRequestParams

Of course, this isn’t really what I want. One option to work around this is to set the ignoreRequestParams property of the document data source to true and compute the documentId property (and, optionally, the action property).

<xp:dominoDocument var="document2" formName="Person"
  action="openDocument"
  documentId="#{javascript:return '0123456789ABCDEF0123456789ABCDEF';}"
  ignoreRequestParams="true">
</xp:dominoDocument>

This is the method that I am in the habit of using and it works well when putting the ID in a scope variable and using that for the computed property value.

The ignoreReuqestParams property tells the data source to ignore the documentId and action properties in the URL and leaves it up to you to manage them.

(Note: Even if you compute the documentId, it will not matter if you don’t set ignoreRequestParams to true; the URL parameters will still override the property value.)

requestParamPrefix

However, there is another way to handle this situation without computing the data source properties — the requestParamPrefix property.

You can set this on a data source and it will look for a separate copy of the documentId and action parameters and use them for that specific data source.

For example, if I set the requestParamPrefix to doc2_, then it will look for URL parameters named doc2_documentId and doc2_action and use those for this data source.

You can add the parameter directly in the page source or find it in the properties panel under All Properties > data > data > [data source]. (This assumes the data source is at the page level. If it’s on a panel, then that would be your starting point to find the data source properties.)

requestParamPrefix_2_requestParamPrefix

Now, I can open two different documents on the same page with a URL like this:

http://127.0.0.2/BlogTesting.nsf/TwoDataSources.xsp?documentId=9E9324F079A7F31885257D06007ADF9C&action=openDocument&doc2_documentId=01F564DFFEE4307A85257D06007AED1D&doc2_action=editDocument

requestParamPrefix_3_SeparateDocuments

With this approach, you do not need to set ignoreRequestParams to true. In fact, if you do, then the URL parameters will be ignored — even if they contain the specified prefix.


XPages Tip: Adding Custom Controls to a Separate Drawer in the Controls Palette

$
0
0

When looking at the Controls Palette in Domino Designer, there is a ‘Custom Controls’ drawer that is automatically populated with all custom controls in the current application. In this post, I’ll show how you can better organize your custom controls by displaying them in additional drawers.

The Custom Controls Drawer

Here’s an example: in this test database I have 5 custom controls. They are automatically added to the ‘Custom Controls’ drawer in the Controls Palette.

ControlsPalette_1_Default

Creating a New Drawer in the Controls Palette

If you want to organize one or more custom controls into a separate drawer, you can set the Category property on the custom control’s properties panel.

ControlsPalette_2_CustomDrawer

Now, this custom control will be displayed separately in the controls palette.

ControlsPalette_3_CustomDrawerInPalette

If you have a large application with a lot of elements, this feature can be helpful in keeping groups of controls together. One great way to use it is to group related controls that are all required together to implement a feature so it’s easy to tell what you need to add to a page in order to make it work.


XPages Tip: Filtering a View Data Source with URL Parameters

$
0
0

If you’re looking for a quick way to manipulate the data returned by a view data source, you can use URL parameters that match the property names. This allows you to effectively compute them without having to write code to compute the parameters. In this post, I’ll show several examples.

Sample View

In my sample database, I have a categorized view in the Notes client.

ViewDataSourceURLParams-1

I added a data source for this view to an XPages and dragged all of the columns on to the page to have it automatically create a view
panel.

http://www.server.com/myDB.nsf/MyPageName.xsp
ViewDataSourceURLParams-1b-XPage

Here’s the data source tag on the page — there are no computed properties.

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

Using URL Parameters to Filter the View

To filter the view, all you have to do is append URL parameters with the same name as a filtering property of the view data source.

To limit the data to a single category, add a categoryFilter parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?categoryFilter=Group 1
ViewDataSourceURLParams-2-categoryFilter

To execute a full-text search, add a search parameter. (The database must be full-text indexed or it will throw an error.) You can also include wildcards in the search parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?search=101
ViewDataSourceURLParams-3-Search

To filter the results based on the first sorted column in the view, use the keys parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?keys=Group 3

Other Actions

To set the view’s starting point, you can use the startKeys parameter. (Note: The view will continue on to the end after the starting point.)

http://www.server.com/myDB.nsf/MyPageName.xsp?startKeys=group 2

To expand or collapse categories in the view, use the expandLevel parameter.

http://www.server.com/myDB.nsf/MyPageName.xsp?expandLevel=1
ViewDataSourceURLParams-4-ExpandLevel

Miscellaneous Notes

These attributes work on the view data source and not specifically on the view panel, so it is useful on a repeat control or any other control that uses a view data source.

If your data source has ignoreRequestParameters set to true, then this will not work because it will – um – ignore the request parameters.

If you enter a parameter that doesn’t correspond exactly to a property name, then it will be ignored by the view data source.


Interesting Quirk with Custom Property Names

$
0
0

I came across an interesting quirk when defining custom properties within a custom control — there are some names that cannot be used.

While working on a reusable control for charting functionality, I wanted to add a custom property called chartTheme. As I started to type the name, it let me type ‘cha’, then prevented the ‘r’ from working. I initially thought something was wrong with the key on my keyboard, because it let me type other characters. After fiddling with it for a moment, I realized that it just refused to allow the property to be named ‘char’.

To work around it, I typed the ‘t’ next and then added the ‘r’ afterwards. (After the word ‘chart’ was in the field, it would not let me delete the ‘t’, which would have changed the word back to ‘char’.)

I tried other data type names and found a similar issue. Then I tried other keywords (true, class, etc) and got the same result.

It looks like a limitation on reserved words in Java in general. (Logically, this makes sense because everything is compiled down to Java.)

I found tested these reserved words and tested them all and verified that they are cannot be used:

  • abstract
  • assert
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • class
  • const
  • continue
  • default
  • double
  • do
  • else
  • enum
  • extends
  • false
  • final
  • finally
  • float
  • for
  • goto
  • if
  • implements
  • import
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • null
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • strictfp
  • super
  • switch
  • synchronized
  • this
  • throw
  • throws
  • transient
  • true
  • try
  • void
  • volatile
  • while

I also noticed that ‘con’ and ‘nul’ are not allowed.

This can be annoying when typing a property name, but it’s easily worked around by adding a different character and then fixing it.

I’m curious to hear if you’ve had similar experience.

1. Are there any other words that you’ve come across?

2. Are there other places where you’ve seen this limitation?


Passing Parameters to SSJS from a Client-side partialRefreshGet()

$
0
0

partialRefreshGet() is a handy method of the client-side XSP object that can be used to trigger a partial refresh from client-side JavaScript. In this post, I’ll show how you can pass parameters for SSJS to read during the refresh, which allows you to send information to the server-side code without submitting a less efficient POST request.

This is an interesting tip that I picked up from the Mastering XPages book. I’ve used partialRefreshGet() numerous times, but I wasn’t familiar with the params property previously.

Here’s an example of a normal partialRefreshGet() call:

XSP.partialRefreshGet("#{id:myComputedText}", {});

The first parameter is the target for the partial refresh. This is client-side JavaScript, so it needs to use the #{id: } syntax to compute the client-side ID of the refresh target.

The second parameter is an object that have up to 4 properties: onStart, onError, onComplete, and params. Here’s an example of the structure when using all of the options (although none are required):

XSP.partialRefreshGet("#{id:myComputedText}",
 {
    params: paramObject,
    onStart: startHandler,
    onError: errorHandler,
    onComplete: completeHandler

 });

The params Property and the param Object

The params property takes an object with parameters to send with the AJAX call. The Mastering XPages book says that the params property “gets expanded, encoded, and appended to the GET request URI that is invoked by the underlying AJAX handler.”

This gives you an easy way to pass information from client-side JS to SSJS and then access it via the param object in SSJS, which provides access to all URL parameters.

The SSJS that’s intended to read the parameters passed by a partialRefreshGet much be within the specified refresh target in order to read the parameters during the refresh.

Simple Example

If I have a computedText component with this value:

if (param.containsKey('parameter1')) {
  return param.parameter1 + ' ' + param.parameter2;
}

It will not return anything when the page first loads.

If I add a button with this client-side JavaScript…

XSP.partialRefreshGet("#{id:computedField2}", 
  {
    params:{"parameter1":"1", "parameter2":"2"}
  });

… it will display 1(space)2 after I click the button, because it is the refresh target and it can read URL parameters sent during the refresh.

This is a very efficient way to send data to a server-side script.

Note: If you pass a parameter that already exists in the URL, it does not overwrite the URL parameter value — it turns the value into a string separated by a comma and a space between the values.


Mask Converters in XPages

$
0
0

If you want to force the data entered by a user into a certain pattern (for structured values such as dates and phone numbers) you can use mask converters. In this post, I’ll show how to implement them and explain what they do (and don’t do).

Adding a Mask Converter

To add a mask converter to a field, select the Data subtab of the field properties and change the Display type value to Mask.

Once you do this, a field will display below for you to enter the mask pattern.

MaskConverter - 1 - Field Property

Primary Input Markers

Mask patterns can contain input markers and literal characters.

The 3 most common input markers are the following:

  • ? – a letter
  • # – a digit
  • A – a letter or digit

You can use these to define a pattern of a specific number of letters and/or digits.

For example, to define a value with 3 letters (such as a country code), the pattern would be ???.

Pretty straightforward.

Input Converter != Input Mask

At this point, it’s important to understand that the result of this might be different than you’d expect.

1) There is no visual indicator that a field is masked.
2) The data entry is not restricted in any way.
3) If you save the form and the data in any field doesn’t match the mask, then it appears that nothing happens.

If you have an Display Error control next to a masked field or a Display Errors control at the top of the page, you’ll see that it throws a “Source string is unmatched with mask pattern.” error in this case. (If you manually enter data that matches the defined mask pattern, the form is saved successfully.)

Even though you may have expected an input mask on the field, the behavior makes sense conceptually because it’s a converter; converters work to format the data after you enter it and submit the form (and before it’s displayed when viewed later).

You’ll need to display the pattern somewhere near the field or you will drive your users crazy by not letting them know how the data needs to be entered.

Input Mask jQuery Plugin

If you’re looking for an input mask, check out this post by Marky Roden regarding a jQuery plugin.

Including Literal Characters

Now back to the mask converter…

Defining the quantity of letters and digits is useful, but it’s often even more helpful to include literal characters to help format the data to increase the readability.

For example, a US phone number is more readable when in this format: (###) ###-####

As I sat to write this post, I did a cursory search and found that Brian Moore has also written about this recently. Take a look at his approach to removing literal characters in a phone number.

Other examples where literals are useful in formatting the data are credit card numbers, social security numbers, and dates (although date pickers are generally much more convenient to work with).

You may also have other patterns that are custom to your organization, such an an invoice number that starts with ‘INV-’. You could have a pattern like this: INV-#####

Computing a Mask Pattern

You can also compute the mask pattern, in case it needs to change based on some other factor. However, it is computed on page load, so do not expect it to change during a page refresh.

I could see a use case where you’d have some kind of identifier that starts with the current year. Here is a simple computed pattern to define this:

var d = new Date();
return d.getFullYear() + '-' + '#####';

The asis property

The asis property determines whether to filter out any literal characters in the mask.

The default is false, which will keep any formatting characters in the data saved to the field.

You can modify the property by selecting the input control, going to the All Properties subtab and then locating the mask under data>converter

Other Pattern Input Markers

There are a few other markers that you can use when defining the mask pattern:

  • H – a hex character (0-9, A-F)
  • * – anything
  • ‘ – escape a formatting character
  • U – convert lowercase to upper case
  • L – lowercase stay lowercase


Changing the Search Behavior of a Dojo Filtering Select in XPages

$
0
0

The default behavior of a Dojo Filtering Select control is to take what you type and filter the options in the list based on what options start with that value. In this post, I’ll show how to change it to search any part of the value (more like a Select2).

Default Filtering Behavior

To demonstrate, I set up this Dojo Filtering Select:

FilteringSelect_SearchMiddle_1

(This post shows the easiest way to create a Dojo Filtering Select)

<xe:djFilteringSelect id="djFilteringSelect2">	
  <xp:selectItem itemLabel="abc"></xp:selectItem>
  <xp:selectItem itemLabel="bcd"></xp:selectItem>
  <xp:selectItem itemLabel="cde"></xp:selectItem>
  <xp:selectItem itemLabel="efg"></xp:selectItem>
  <xp:selectItem itemLabel="fgh"></xp:selectItem>
  <xp:selectItem itemLabel="ghi"></xp:selectItem>
  <xp:selectItem itemLabel="hij"></xp:selectItem>
</xe:djFilteringSelect>

As I type a letter, it filters the list down to any values that start with that letter:

FilteringSelect_SearchMiddle_2

Searching Any Part of the Value

If you want to change the behavior to match any part of the value when searching, you can update the queryExpr property. Dojo documentation says that you need to set it to "*${0}*" for the desired outcome.

${0} will return the value that the user has typed into the field so far. The default behavior is "${0}*", but if you also add the wildcard (*) before the search term, it will look for the term anywhere in the value.

Updating queryExpr in XPages

The Dojo Filtering Select control has a queryExpr property. However, entering this search term does not bring the desired result.

If you enter *${0}* into the property (XPages will automatically enclose all attribute values in double quotes), it looks good in the source of the page…

<xe:djFilteringSelect id="djFilteringSelect2" queryExpr="*${0}*">

… but it breaks the field (you get a default value, but no drop-down list) because it ends up sending this to the browser:

<select dojoType="dijit.form.FilteringSelect" queryExpr="*0*" id="view:_id1:djFilteringSelect2" name="view:_id1:djFilteringSelect2">

It is automatically removing the $, {, and } characters.

Fortunately, we can fix this pretty easily by computing the value and escaping each of those characters with a backslash (\).

return '*\$\{0\}*';

Now our source tag in XPages looks like this:

<xe:djFilteringSelect id="djFilteringSelect2"
  queryExpr="#{javascript:return '*\$\{0\}*';}">

This allows it to pass the value through to HTML properly, which fixes the field and enables the behavior that we’re looking for.

If I type a ‘c’ into the field, I know see a list filtered to all options that have a ‘c’ anywhere in the value!

FilteringSelect_SearchMiddle_3

Updating the Highlighting Behavior

When you change the default search behavior, the highlighting of the value in the field seems odd. I type a ‘c’ into the field, and it auto completed the field with the first value that contained a ‘c’, but highlighted everything after the first character (since I type in 1 character).

This now seems counterintuitive since it’s not only filtering from the front of the list.

Using the autoComplete property of the Dojo Filtering Select, we can stop this behavior.

If you set autoComplete to false, then it won’t automatically fill in the first matching value.

FilteringSelect_SearchMiddle_4

I like this a lot more from a usability perspective. Just be aware that, since it’s not autocompleting with a valid value, if you leave the field before selecting a value, you’ll get an error because the field does not contain a valid value. (Although that validation can also be turned off.)

Here is the full source of my field, including these updates:

<xe:djFilteringSelect id="djFilteringSelect2"
  queryExpr="#{javascript:return '*\$\{0\}*';}" autoComplete="false">

  <xp:selectItem itemLabel="abc"></xp:selectItem>
  <xp:selectItem itemLabel="bcd"></xp:selectItem>
  <xp:selectItem itemLabel="cde"></xp:selectItem>
  <xp:selectItem itemLabel="efg"></xp:selectItem>
  <xp:selectItem itemLabel="fgh"></xp:selectItem>
  <xp:selectItem itemLabel="ghi"></xp:selectItem>
  <xp:selectItem itemLabel="hij"></xp:selectItem>
</xe:djFilteringSelect>

NotesIn9 Episode 147 – dGrowl in XPages

$
0
0

NotesIn9 episode 147 demonstrates how to implement the dGrowl plugin to add growl-style messages to an XPages application. This provides a nice UI for a different style of message to display to the user and it allows you to set an automatic timeout or display the message until the user closes it. More importantly, the demo shows how to incorporate a Dojo plugin into an XPages application.

I set up a page in my demo application to test it out.

The plugin comes with two message styles: info and error. In my next blog post, I’ll show how to enhance it to add success and warning styles.


Adding New Message Styles to dGrowl

$
0
0

In NotesIn9 episode 147, I demonstrated how to implement the dGrowl Dojo plugin in XPages. The plugin comes with two message styles: info and error. In this post, I’ll show how to enhance it to add success and warning styles.

dGrowl_Enhanced

Take a look at the live demo page to see these in action.

In order to add a new message type, all you have to do is add a few lines of CSS to define the new message style and update the dGrowl object creation code to add the new channel.

Adding New Message Styling

This starts with the assumption that you have already implemented the dGrowl plugin in your application, as shown in the NotesIn9 video.

You’ll need to go through Package Explorer to locate the stylesheet, since it’s part of the plugin files installed under the WebContent folder.

dGrowlCSS

Open dGrowl.css and add rules for additional message styles.

Here’s an example that I set up by copying the .dGrowl-channel-error block styling. I changed the class name and updated the color scheme (based on the OneUI message styling).

/* 'Warning' Channel */
.dGrowl-channel-warning .dGrowl-notification {
  background-color: rgb(255, 255, 188);
  border: 1px solid rgb(246, 230, 146);
}

/* 'Confirmation' Channel */
.dGrowl-channel-confirmation .dGrowl-notification {
  background-color: rgb(236, 249, 223);
  border: 1px solid rgb(200, 226, 184);
}

Adding the New Message Channel

In the script block that instantiates the new dGrowl object, just add two additional channels and define the position number to order them.

<script type="text/javascript">
  var dg = new dGrowl({'channels':[
    {'name':'error', 'pos':1},
    {'name':'warning','pos':2},
    {'name':'confirmation','pos':3},
    {'name':'info','pos':4}
  ]});
</script>

The key is that the channel name must match the end of the class name in the CSS. (For example: .dGrowl-channel-confirmation styling will be used by the channel named confirmation) If the names don’t match, then your message will get the default (info) message styling.

Now the channels are set up and ready for messages.

dg.addNotification('Warning Message',{'channel':'warning', 'sticky':true});]]>
dg.addNotification('Confirmation Message',{'channel':'confirmation', 'sticky':true});

Displaying a dGrowl message from SSJS

$
0
0

In a recent NotesIn9 video, I showed how to use the dGrowl Dojo plugin to create growl-style messages in XPages. Jesse Gallagher and Frank Van der Linden showed how to trigger growl-style message from server-side code with Java. In this post, I’ll round out the discussion with an SSJS snippet to do the same.

view.postScript()

As in Jesse’s and Frank’s examples, the key method here is view.postScript(). This method adds a client-side snippet to run after a server-side refresh occurs. I believe it has been available since 8.5.3.

As Jesse mentioned, the biggest challenge here is usually escaping characters properly, remembering that you’re using server-side code to write out client-side code.

The concept is simple, though — take the client JS from an example message and, if it only uses single quotes, wrap it in double quotes and pass it through.

var notificationJS = "dg.addNotification('Here is an info message...',{'channel':'info', 'duration': 3000});";
view.postScript(notificationJS);

Full Refresh vs Partial Refresh

This works fine with both full and partial refreshes. However, if you use a partial refresh, you would have the ability to run the script multiple times and display separate messages (as needed), whereas a full refresh would clear all messages because it refreshes the entire page.


XPages Tip: Disabling Required Validation in a Dojo Filtering Select

$
0
0

Dojo Filtering Select (xe:djFilteringSelect) controls include client side ‘required’ validation by default. The problem is that if it fails this validation, any page submission or other server-side action will not be triggered. However, if you want to disable this validation, the built-in property of the control doesn’t work. In this post, I’ll show how to achieve the desired effect.

Creating a Filtering Select

If you’re not familiar with the Dojo Filtering Select, take a look at this post.

Validation Behavior

Take, for example, the Dojo Filtering Select that I used in a recent post about changing the search behavior of a Dojo Filtering Select:

FilteringSelect_Required-1

If I clear the value in the field and tab out of it, I am presented with this error message: ‘This value is required’

FilteringSelect_Required-2

The problem is that any server-side onChange error handler of the field will not fire because the field failed client-side validation.

Disabling the Required Validation

The Dojo documentation shows that adding a required attribute and setting it to false will disable this behavior.

There’s a required property on the djFilteringSelect control. Unfortunately, it has no effect when set to false.

If you look at the HTML output, you’ll see that the field has this attribute: aria-required="true"

To get it to work, you can add the required attribute (and set it to false) as a Dojo attribute.

FilteringSelect_Required-3

This does the job and it changes the attribute in the HTML output for the page to: aria-required="false"


Viewing all 216 articles
Browse latest View live