Archive | Uncategorized RSS for this section

Handling Errors in an XPages RPC Method

The Remote Service (aka xe:jsonRPCService) is an extremely useful control in XPages because it examples client- and server-side code interaction, runs asynchronously, performs well, and is easy to use. But if you don’t handle errors well, it can fail quietly and the user may never know. In this post, I’ll show how to handle client- and server-side JavaScript errors with an RPC method.

Remote Procecure Example

As a starting point, let’s look at an example of a simple RPC method that returns the date and time and displays it for the user.

RPC Control

Here’s the XPages component source:

<xe:jsonRpcService id="jsonRpcService1" serviceName="myRPCService">
  <xe:this.methods>
    <xe:remoteMethod name="myMethod" script="return myLibraryFunction();">
    </xe:remoteMethod>
  </xe:this.methods>
</xe:jsonRpcService>

The service name is myRPCService. The method, myMethod takes no parameters and just calls an SSJS library function named myLibraryFunction().

SSJS Library Function

Here’s the SSJS function that it calls:

function myLibraryFunction() {
  var d = new Date();
  return d.toLocaleString();
}
Client-Side JavaScript

Here’s the code that calls the RPC method:

myRPCService.myMethod().addCallback(function (response) {
  alert('response: ' + response);
})

It calls the method in the RPC service and attaches a callback function to wait for the response. It then displays the response to the user in an alert.

RPC Error Handling - A

Handling Client-Side Errors

This works well and RPC functionality is awesome, but you have to be careful about how you handle errors.

Take for example, this problematic update. This code ignores the response, but tries to display an invalid value (an undeclared variable) in an alert.

myRPCService.myMethod().addCallback(function (response) {
  console.log('before');
  alert ('Invalid variable: ' + myUndeclaredVariable);
  console.log('after');
})

When you run the code, it appears that nothing happens. The console shows the ‘before’ statement, but it then fails quietly.

Putting a try-catch block around it like this doesn’t help at all.

try {
  myRPCService.myMethod().addCallback(function (response) {
    console.log('before');
    alert ('Invalid variable: ' + myUndeclaredVariable);
    console.log('after');
  })
} catch (e) {
	alert('Error: ' + e.toString());
}

This may seem a bit confusing, but it actually makes sense. The callback effectively runs in its own scope, so the error handling needs to be within the callback in order to fire when dealing with an RPC call.

This code does the trick:

myRPCService.myMethod().addCallback(function (response) {
  try {
    console.log('before');
    alert ('Invalid variable: ' + myUndeclaredVariable);
    console.log('after');
  } catch (e) {
    alert('Error: ' + e.toString());
  }
})

RPC Error Handling - B

Handling Server-Side Errors

If there’s an unhandled exception on the server-side code that runs (such as an error or forgetting to return a response), it also fails quietly, although it will show a few errors in the browser console.

RPC Error Handling - C

If you expand the POST, you’ll see that it returns a stack trace for an RPC error.

In this case, error handling in the client-side callback function doesn’t help at all, so it’s important to handle the error in the server-side code and return something that the callback can deal with.

function myLibraryFunction() {
  try {
    print (myUndeclaredVariable);
    var d = new Date();
    return d.toLocaleString();	
  } catch (e) {
    return 'Error: ' + e.toString();
  }
}

RPC Error Handling - D

Now, I’m returning a more informative message to the user about what went wrong.

I generally like to set up my server-side methods to return an object to the callback function, because that way I can add as many properties as I want in order to return all of the information that I need. I generally include a property for a boolean value for whether the method was successful and another value that contains a success or error message. In the callback, those values can be checked and appropriate action can be taken accordingly.

Advertisements

Speaking at Connect

At Connect next week, I’ll be co-presenting two Best Practices sessions, one on grids in XPages with Paul Calhoun and the other on web apps and IBM Digital Experience with John Head.

AD-1207: The Grid, the Brad, and The Ugly: Using Grids to Improve Your Applications

Tuesday @ 5:15pm

Do you want better features, better performance, and a better UI in your XPages applications? Then display your data in grids instead of built-in controls. In this session, Paul and Brad will demonstrate why grids are a significant improvement in general and cover why one size does not fit all. They will review the features of commonly-used JavaScript grid frameworks (including Dojo, jQuery, Kendo UI, and Sencha) in order to help you determine which is the best fit for your applications.

 

AD-1539: Bringing Your Web Apps to IBM Digital Experience

Tuesay @ 10:45am

For too long, WebSphere portal has been seen as the realm of the back end developer with specialized Java skills. This has been a barrier to entry to the IBM Domino community. IBM has transformed the product to the IBM Digital Experience platform – and it’s not just a name change! With the inclusion of the Script Portlet & IBM Portal on Cloud option, it’s time to look again. We will show you how to integrate your XPages applications, Bluemix and even Microsoft SharePoint. We will show content re-purpose without migration. If you are looking for a single point of integration for all your apps, this session is for you!

 

Hope to see you there!

Gridx in XPages – 16: Advanced Searching with the FilterBar Module

In the last post, we looked at simple full-text searching with the QuickFilter module. In this post, I’ll show how to use provided more advanced search capabilities with the FilterBar module, which allows for multiple rules, column-specific searching, and all or any rule matching.

Gridx Series

Gridx in XPages — Entire Series

FilterBar

The FilterBar module is simple to add and provides great search functionality. When added to the grid, it provides — wait for it — a filter bar at the top of the grid.

Gridx 16 A

By default, it tells you that no filter is in effect. When you click on the button in the upper left hand corner, you are presented with the filter dialog.

Gridx 16 B

The Column drop-down lets you choose to search any column or to choose a single grid column to search.

Gridx 16 C

The Condition drop-down gives you several options for the filtering condition — contains, equal, starts with, ends with, etc. This provides a lot of functionality for your searches.

Gridx 16 D

The Value field is where you enter the search value. If you have selected a column to search, you will get type ahead for values in that column to optionally choose from.

Gridx 16 D2

The plus (+) icon in the lower left gives you the ability to add more rules to the filter. In this example, I added 3 rules to match.

Gridx 16 E

When I executed my search, it returned a single row and the filter bar tells me that it’s showing 1 out of 1301 rows. It also provides a link to clear the filter. (The ‘x’ icon closes the filter bar.)

Gridx 16 F

The Match drop-down gives you the ability to allow the search to work on a combination of all rules or to include rows that match at least one of the rules.

Gridx 16 G

If I change the Match from all rules to any rule, I get more results.

Gridx 16 H

Implementing FilterBar

Adding FilterBar is very straightforward; you just need to add two more modules to the grid.

Here’s the updated require() in my example:

require([ 
  "gridx/Grid", 
  "dojo/store/Memory",
  "gridx/core/model/cache/Sync", 
  "gridx/modules/ColumnResizer",
  "gridx/modules/NestedSort", 
  "gridx/modules/Filter",
  "gridx/modules/filter/FilterBar",
  "dojo/domReady!" ], 
  function(Grid, MemoryStore, Cache, Resizer, NestedSort, Filter, FilterBar) {

And here is the updated grid object:

grid = new Grid({ 
  id: "my_gridX", 
  cacheClass: Cache, 
  store: store, 
  structure: columns, 
  modules: [ 
    Resizer, 
    NestedSort,
    Filter,
    FilterBar
  ] 
});

That’s it!

Combine with QuickFilter

You can use both QuickFilter and FilterBar together in the same grid to provide quick full-text searching and rule-based advanced filtering.

Just add both modules and the filter base (gridx/modules/Filter)!

Local Data Only

Note: This will only work simply on a local data store, so I am using an AJAX request to pull the data from a REST service locally.

If you are using a remote data store, you’ll need to filter the data server-side before sending it client-side.

Unique IDs Required

Note: If your REST service provides data from a categorized row or a totals row at the end, it can cause filtering functionality not to work properly. This is because the grid requires each row to have a unique ID (which we’ve set to use NoteID in our examples), but category rows and totals rows don’t represent documents so they do not include a NoteID.

It does not cause an obvious error but filtering doesn’t work, the page freezes and you eventually get a message asking you about stopping or debugging JavaScript.

Claro Theme Required

As mentioned in a previous post, the claro theme must be used properly for this to work well.

Without it, the filtering dialog looks like this — it’s not even distinguished from the rest of the screen:

Gridx 16 I

Up Next

In next post, we’ll look at how to filter based on non-string columns, such as dates and numbers.

Setting the Maximum File Upload Size for an XPages Application

If you want to control the maximum value for an uploaded file, you can use the xsp.upload.maximumsize setting in xsp.properties.

Application-Level Maximum Upload Size

There is no maximum upload set at the application level by default. (Although there is a server-level setting that I’ll come back to later in this post.)

To set it, you can use the Xsp Properties design element and set the Maximum size property under File Upload Options in the first column of the General tab. Specify the value in kilobytes (KB)

MaxFileUploadTesting-0-Setting

This adds the following value to the xsp.properties file (as seen on the Source tab):

xsp.upload.maximumsize=400

Error Message

If you add an Error Message control for the File Upload control or an Error Messages control on the form, you will see an error message regarding the file size setting when you try to submit a form with an attachment that’s too large.

MaxFileUploadTesting-1-Error

Server-wide Limit

As mentioned earlier, there’s no default at the application level. The default is the server-wide setting, which defaults to roughly 10 MB.

Even if you set the maximum at the application level, it can never exceed the server setting.

The server setting is defined on the Server document in the Domino Directory. It can be found on the Internet Protocols tab, HTTP subtab in the HTTP Protocol Limits section.

MaxFileUploadTesting-3-ServerSetting

If you try to upload a file larger than the server-wide limit, it aborts the connection and throws an ugly error. (HTTP 500 – Internal Server Error)

MaxFileUpload-ServerError

Even if you set an application level maximum lower than the server maximum, if you try to upload a file larger than the server maximum, it will throw the same HTTP error.