Archive | April 2014

Dojo in XPages – 20: Handling Successful or Failed AJAX Requests

In the last post, I showed how to use an xhr.get() request in Dojo to asynchronously retrieve information from a REST service. In this post, we’ll look at how to execute code when the request is completed or returns an error within an example that demonstrates how to display the response (or an error message) on the page.

Dojo in XPages Series

Dojo in XPages — All Blog Posts

XHR Callbacks

The Dojo xhr requests provide the opportunity to define up to 3 callback functions that run after the request is completed. The xhr request is generally asynchronous (although there’s a parameter to change that), so it doesn’t block the user from interacting with the rest of the page while data is retrieved. The callback functions are useful in that they can see the results of the request and respond accordingly. All callbacks are anonymous javascript functions that automatically receive at least one parameter.

load – the ‘success’ callback

As shown in the last post, the load callback is executed when the request is completed and data has been retrieved successfully. The function automatically receives a parameter that contains the data that was returned by the request, in the format specified by the handleAs parameter (generally text, json, or xml).

error – the ‘failure’ callback

The error callback is executed when the request cannot be completed successfully. The function automatically receives a parameter defining the error and can also use a second parameter to determine the HTTP status code (among other things).

handle – the ‘always’ callback

In addition to load and error, there is another callback option called handle. This callback runs regardless of whether the call was successful or failed. You can review the response and determine whether it was successful based on the data. This is an option if you want to have some code run regardless of the response and you don’t want to duplicate it in both the load and error callbacks.

An Example

Building on the example shown in the last post, this code will request data from a REST service. If successful, it will write the data onto the page in the form of a table (assuming there’s a passthru HTML div on the page with the ID “resultsDiv”). If it fails, it will display a message in that div in red.

dojo.xhr.get({
  url:"REST.xsp/People",
  handleAs:"json",
  load: function(data){
    var output = '<table>';

    // Build the header row by inspecting column names
    output += '<tr>';
    for (var col in data[0]) {
        output += '<th>' + col + '</th>';
    }
    output += '</tr>';

    // Build the data rows
    for(var i in data){
      output += '<tr>';
      for (col in data[i]) {
        output += '<td>' + data[i][col] + '</td>';
      }
      output += '</tr>';
    }
    output += '</table>';
    dojo.byId('resultsDiv').innerHTML = output;
  },
  error: function(msg, args) {
    dojo.style('resultsDiv', 'color', 'red');
    dojo.byId('resultsDiv').innerHTML = 'Status: ' + args.xhr.status + '<br />' + msg;
  }
});

When successful, in inspects the structure of the data returned and builds a table to display it:

Dojo 20 - A - Display REST Data

To test out the error code, just point it at a page that doesn’t exist.

Dojo 20 - B - Display REST Error

Dojo in XPages – 19: Using AJAX to Retrieve Data from a REST Service

AJAX is a critical component to creating applications that are highly responsive (performance-wise) in the browser. When you initiate an asynchronous request, the rest of the page is not blocked while some server action is executed. AJAX wrapper classes are built into the Dojo base module, so they’re automatically available to use in XPages. In this post, I’ll show how you can make an AJAX call with Dojo to retrieve data from a REST service in XPages.

Dojo in XPages Series

Dojo in XPages — All Blog Posts

The Test Data and REST Service

I created some test documents that have FirstName, LastName, and Address fields. I created an XPage named REST.xsp and added a REST service (viewJsonService) to provide the data. The pathInfo property of the REST service is set to People, so the URL to reference it from within the same application is REST.xsp/People.

Here is the source of the REST service:

<xe:restService id="restService1" pathInfo="People">
  <xe:this.service>
    <xe:viewJsonService defaultColumns="true"
      viewName="People">
    </xe:viewJsonService>
  </xe:this.service>
</xe:restService>

Here’s what the data looks like when I display it in the browser:

Dojo 19 - A - REST Data

Tip: Remember to always test your REST service output in the browser so you can verify that it’s returning data that you expect.

Retrieving the Data with AJAX

To retrieve that data from another XPage, I can use this dojo code:

// Retrieve data from a REST service and write it out to the console
dojo.xhr.get({
  url:"REST.xsp/People",
  handleAs:"json",
  load: function(data){
    for(var i in data){
      console.log("#" + i + ": value", data[i]);
    }
  }
});

XHR is short for XMLHttpRequest — the object that’s used to make an asynchronous request. xhr.get() is the Dojo wrapper function for making that asynchronous call from client-side JavaScript.

The url parameter refers to my page with the REST service (including the pathInfo property that refers to a specific REST service). This can be any URL that you need.

The load property is a callback function that runs after data has been retrieved. It’s an anonymous function that automatically receives a handle to the data that was retrieved. The parameter name can be whatever you want.

Since the JSON data returned by the REST service is an array of objects, this code loops through the array and prints the retrieved data to the console.
Dojo 19 - B - REST Data

And there you have it – an asynchronous call that retrieves data and writes it out to the console.

In the next post, I’ll dig a little more into the callbacks and demonstrate displaying the returned data on the page.

Improving the Responsivness of an XPage/Custom Control with a View Panel in Domino Designer

In his presentation during the recent TLCC webinar, Mark Roden had some great tips on speeding up Domino Designer. During the open Q&A period, a question about improving the responsivness of DDE with a page containing a view panel was raised. In this post, I’ll provide a few tips to help.

The Problem

There are times when there is a significant delay in Domino Designer (DDE) when attempting to view or modify properties of a View Panel control. Even in the source view, you may change a property and wait several seconds (or more) between each keystroke. Just clicking on the panel or a column or a subtab in the properties view can be very slow. With every click or keystroke DDE appears to be resolving the data source. The lag can become extremely frustrating, based on machine, server, and network performance. The constant delays can be a significant detriment to your ability to be productive.

Fortunately, there are a few things you can do to improve the situation.

Ensure that DDE Memory Settings are Correct

This tip isn’t view-specific, but for DDE performance in general.

When you install Domino Designer, the default memory settings are far too low. See this TLCC tip for information on how to provide more memory to Domino Designer, thus dramatically speeding up its performance.

Even if you fix the settings, they will be reverted when you upgrade to a newer version of Domino Designer.

Work Locally

The lag in working with a view panel is usually far, far, far (did I say “far”?) worse when working over a network on the server. If you can replicate the application locally for your development and replicate frequently to the server for testing, you will generally see a significant improvement in the responsiveness of Domino Designer when working with the view panel.

Compute the Data Source

If you cannot work on a local replica (or if that doesn’t speed up performance enough), you can compute the view’s data source.

When the data source is computed, Domino Designer no longer attempts to resolve it and read information every time you click on any part of the panel or use any keystroke to modify a property.

Originally, the view data source will look something like this:

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

When you compute the source, it looks more like this:

<xp:this.data>
  <xp:dominoView var="view1"> 
    <xp:this.viewName>
      <![CDATA[#{javascript:return "myViewName";}]]>
    </xp:this.viewName>
  </xp:dominoView>
</xp:this.data>

This provides a massive improvement in responsiveness — even when working on a remote server.

However, since the data source is not being resolved by Domino Designer, you will lose column selection drop-downs.

My recommendation is to implement the view panel and drag-and-drop the columns that you’d like in the view, then change the data source to be computed and modify formatting or other view properties after that.

Note: If you’re pointing to a different server or different database name, compute both of those properties as well to gain this performance benefit.

Adding Event Handlers to Font Awesome Icons in XPages

In the previous two posts, I showed how to implement Font Awesome in XPages and two options for adding icons to your page. In this post, I’ll show how you can add event handlers so that you can trigger an action when a user clicks on an icon.

Add a Client-Side Event Handler with Dojo or jQuery

If you want to trigger a client-side event, you can use Dojo or jQuery to add an event handler to the icon after the page loads.

For example, if you have this bullseye icon…

<i id="myIcon" class="fa fa-bullseye"></i>

…and you want to add an event handler to display an alert when the user clicks on it, you can use this Dojo code:

dojo.on(dojo.byId('myIcon'), 'click', function() {
  console.log('clicked icon');
});

Here’s more information about attaching event handlers (you may need to include the dojo.on module) and event delegation in Dojo.

Add Icon Within an XPages Control

Another option for making icons clickable is to put them inside of another XPages control that has an event handler. For example, you can create a link control, button control, span control, etc and put a font awesome icon inside of it.

Here’s an example of displaying an icon within an XPages button. It displays a message in the console with client-side JavaScript and also triggers a server-side partial refresh of a panel.

To add the icon, you have to switch to the source view and add it directly.

<xp:button value=" Click Me" id="button1">
  <i id="myIconButton" class="fa fa-bullseye"></i>
  <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="myPanel">
    <xp:this.script><![CDATA[console.log('clicked icon button');]]></xp:this.script>
  </xp:eventHandler>
</xp:button>

FontAwesomeButton

Notice that it turns the icon blue by default. It does the same when inside of a link, because the browser makes link text blue by default (and these icons are implemented as a font, so therefore, the browser is correctly treating them as text).

Here’s an example of displaying an icon (with the same effect) within an XPages link:

<xp:link escape="true" text="" id="link1">
  <i id="myIconLink" class="fa fa-bullseye"></i>
  <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="myPanel">
    <xp:this.script><![CDATA[console.log('clicked icon link');]]></xp:this.script>
  </xp:eventHandler>
</xp:link>

Add an XPages Event Handler Directly to an Icon

In my last post, I mentioned that I prefer to use computed text fields with the tagName property set, because you can set a rendered formula and compute the class names as needed. Another advantage to that approach is that you can attach an XPages event handler, so you can add server side code, partial refreshes, onComplete callbacks, etc.

Now, that comes with a significant caveat, because Computed Field controls do not provide the ability for you to add events in the “pretty panels”.

However, if you add an event handler to another control, you can go into the Source and move that event handler into the Computed Field (xp:text) control and it will fire.

In this example, I created a Computed Field to display an icon and I copied the event handler from the previous example into it.

<xp:text escape="true" id="computedField2" tagName="i"
  styleClass="fa fa-bullseye fa-3x">
  <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="myPanel">
    <xp:this.script><![CDATA[console.log('clicked icon link');]]></xp:this.script>
  </xp:eventHandler>		
</xp:text>

If you go into the source and click on the xp:eventHandler tag, you’ll get a property panel where you can bring up the client or server JavaScript editor or add other callbacks.

FontAwesomeEventHandler

Now, I have a clickable icon with no extraneous tags around it.

It is certainly simpler to wrap an xp:span tag around an icon to get the same effect, but if you need the clickable icon without additional tags, this provides a way to do it.

Tip – Changing the Cursor when Adding an Event Handler to an Icon

If you’re going to make standalone icons clickable, the text cursor may be confusing (at least in IE and Firefox). (Remember — it’s actually a font, so this makes sense).

If you want to change the cursor when hovering over an icon, you can add this CSS:

i.fa {
  cursor:pointer;	
}

Of course, this will affect the cursor over all font awesome icons in your application. You can target the CSS as needed to only modify it for icons that are clickable.

Using Font Awesome Icons in XPages

In the last post, I showed how to implement Font Awesome in your XPages application. In this post, I’ll show two ways to display Font Awesome icons on your pages.

Option 1 – Pass-through HTML

Font Awesome icons are not XPages controls, so you can add them to your page directly with pass-thru HTML, an <i> tag. The Font Awesome CSS looks for this tag and replaces it with the correct icon, based on the class name that you provide.

Icon tags generally take this form:

<i class="fa fa-XXX"></i>

Here’s an example of the crosshairs icon:

<i class="fa fa-crosshairs"></i>

FontAwesome_2_Icon

This page contains all icons and their corresponding class names.

Option 2 – Computed Text

Another option you have for adding an icon within XPages is a computed text control.

Since it’s an xp control, you can do more with it, such as conditionally rendering the icon or conditionally computing the class name to change which icon is displayed.

One way to use a computed text control would be to set the Content type property to HTML (which sets escape="false" in the source) and use JavaScript to compute the HTML output.

Here’s an example that will generate the same icon shown above:

<xp:text escape="false" id="computedField1">
  <xp:this.value>
    <![CDATA[#{javascript:return '<i class="fa fa-crosshairs"></i>';}]]>
  </xp:this.value>
</xp:text>

This adds the icon, but also puts a <span> tag around it (as the Computed Field control always does by default).

Here’s the HTML output:

<span id="view:_id1:computedField1" class="xspTextComputedField">
  <i class="fa fa-crosshairs"></i>
</span>

A better method is to use the tagName property of the Computed Field control (as I described in this post).

When you do this, you don’t have to compute any value for the control — just set the tagName to i and set the Class to define the icon that you want. You also don’t have to set the Content type to HTML.

Here’s what it looks like in the XPages source:

<xp:text escape="true" id="computedField2"
  styleClass="fa fa-crosshairs" tagName="i">
</xp:text>

This generates only the HTML that you really want for the icon, without the extraneous <span> tag mixed in. Most of the time it’s probably not a big deal, but it has the potential affect your UI.

<i class="fa fa-crosshairs"></i>

More on Using Font Awesome

You can change the size, orientation, and color of Font Awesome icons (and much more!). You can even stack multiple icons (but not in older IE) to create unique images.

Check out this post by Russ Maher or the Font Awesome site for more information.

Up Next

In the next post, I’ll show how to add an event handler to a Font Awesome icon in XPages.

Implementing Font Awesome 4.0.3 in XPages

Font Awesome is a great library of icons (implemented as a font) that you can use in your applications. Russ Maher wrote a great post and provided a sample application to make it very easy to get up and running with Font Awesome quickly. If you want to use version 3.2.1, stop reading this post and follow Russ’ instructions, because that’s the fastest way to go. However, Font Awesome is now up to version 4.0.3 and if you want to use that (or any future version), you can follow the process outlined here — including an XPages-specific gotcha.

Adding Font Awesome to Your Application

1) Download Font Awesome
http://fortawesome.github.io/Font-Awesome/

2) Extract the files somewhere on your hard drive

3) Add the files to your application

Open in Package Explorer or Navigator in DDE. Drag the font awesome folder from the file system into the WebContent folder in your application.

FontAwesome_WebContent

4) Include Font Awesome CSS

You need one of two stylesheets: font-awesome.css or font-awesome.min.css.

You can add them directly as a page resource (but you’ll have to type in a longer file path, since they’re not Style Sheet design elements — see Russ’ sample database for an example) or include them application-wide in a Theme.

<resources>
  <styleSheet href="font-awesome-4.0.3/css/font-awesome.css"></styleSheet>
</resources>

When going to production, use font-awesome.min.css instead of font-awesome.css.

If you’re using a version other than 4.0.3, update the file path accordingly to match the folder name under WebContent.

Common Error

To try it out, I added an icon tag to an XPage:

<i class="fa fa-users"></i>

In Firefox and Chrome, it doesn’t work by default. (Surprisingly, it does seem to work at this point in IE9+. There are special stylesheets to use font-awesome in IE8 and IE7, but that’s outside of the scope of this post.)

Here’s what it looks like in Chrome, along with the errors in the console (click the image to see it larger):

FontAwesome_Error_Chrome

Here’s what it looks like in Firefox, along with the errors in the console (click the image to see it larger):

FontAwesome_Error_Firefox

They’re both showing “Bad Request” errors. This has to do with URL parameters included for the font references in the Font Awesome stylesheets.

Fixing the Links

The ?v=4.0.3 appended to each font reference is what’s causing the problem. The server does not seem to like those parameters.

To allow it to work within XPages, open up the Font Awesome stylesheet (via Package Explorer or Navigator) and update the font links. You can find the lines to fix at the top of the stylesheets, in the @font-face { } rules.

@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.eot?v=4.0.3');
  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');

All you have to do is remove the ?v=4.0.3 from each url to fix the problem.

In the links that include anchor links (such as: ?#iefix&v=4.0.3), just remove the 4.0.3 part and you can leave the anchor link.

@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.eot');
  src: url('../fonts/fontawesome-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff') format('woff'), url('../fonts/fontawesome-webfont.ttf') format('truetype'), url('../fonts/fontawesome-webfont.svg#fontawesomeregular') format('svg');

(Make the change in both font-awesome.css and font-awesome.min.css.)

Now my sample page shows the “Users” icon.

FontAwesome_Icon

Fixing an “Object has been removed or recycled” error when searching a view data source

I troubleshot a maddening issue in an XPages application recently, so I’m documenting it in case anyone else comes across it (or has a better solution).

The Problem

In a pretty straightforward application, I have repeat controls with view data sources. The search property of each data source is set to read from a scope variable. (When the user executes a search, the button will build a search string and store it in the scope variable.)

I received numerous reports of an “Object has been removed or recycled” error when executing searches. Sometimes, users would report null pointer errors.

There was no pattern — the same search that triggered the error would work immediately after the error was thrown when the page was refreshed. The same search would work fine the next time.

I could never reproduce the error, but as soon as several testers hit the application, they would see it fairly frequently.

Troubleshooting Steps

I’m well aware of the conflicts that can happen (even across scripts) by recycling Notes/Domino objects, but there’s not a whole lot of code and virtually none of it has to recycle anything! But I took all recycle statements out anyway and the problem did not go away.

I also made sure that every piece of code (even on every computed field just reading from a view column) was wrapped in a try – catch block to see if there’s a trappable error, but no script caught anything.

The Solution

So, I searched for similar reports of the error and found an unrelated issue (related to the pager save state control in a data view), but the solution mentioned in the comments sounded like something worth trying.

Changing the application-level Server page persistence property (in XSP Properties) from “Keep pages in memory” to “Keep pages on disk” solved the problem immediately.

Page Persistence

Is there a better solution? It seems like a pretty significant change to have to make when that may not be the best option for the application overall.