dominoGuru.com

Your Development & Design Resource

IBM Domino XPages SSJS Object Literal Primer

JavaScript Objects Overview

I wanted to take a moment to cover a JavaScript technique that I've had great success lately. Lately meaning the past few years... and I think it's time to share.

If you're unfamiliar with JavaScript Objects, here's the basic syntax:

Our example Object has four properties, each with a different type:

  1. Number
  2. String
  3. Boolean
  4. Array

To use these properties, you can use the following syntax:

The above example script will print Number "1" to the web browser console.

Fairly simple and standard... but this becomes amazingly powerful when you realize that you can create Methods as well as Properties. Let's revisit our example:

Now, to use our new Method:

Let's take this a step further:

And now if you wanted to print Number "2" to the web browser console...

Server Side JavaScript Use

OK, so now that you're at least familiar with the JavaScript Object Literal syntax... let's talk about IBM Domino XPages and how you can best leverage this technique in SSJS.

My applications contain both "core.jss" and "application.jss" Server Side JavaScript libraries. The "core.jss" contains various utility functions that I've cobbled together over the years, while -- for applications where the business and application logic reside in SSJS vs. Java -- "application.jss" stores said logic functions and other application-specific script.

Let's say we have a time tracking app that consists of (stateful) "punch" records. Each "punch" will be a notesDocument.

Standard stuff really... which is why this is a perfect example for a simple SSJS implementation of business and application logic. And our "application.jss" library will handle all CRUD (Create, Read, Update, and Delete) operations for our "punch" and "employee profile" records.

There's a lot to cover here...

First, you may be wondering why we're using method names like punch.submit() vs. punch.save() and punch.remove() vs. punch.delete(). Both save() and delete() have existing functionality in JavaScript... and the last thing you want is operator conflicts. They could just as well be blah() and foo(), but that doesn't make for readable code.

Note: .submit() is also a reserved word, but I've yet to run into a conflict using it as a method name. YMMV, so feel free to name your method something like .crudSubmit() if you want to protect yourself and your production code.

Second, you may notice the use of arguments used to allow for conditional parameters to be passed through and used by a method. The .submit(), .edit(), .open(), and .remove() functions all allow you to pass through a notesDocument for processing.

We'll cover several use cases for how we're using the conditional notesDocument argument (arguments[0]) later in this article.

On line 83 of our example, you'll see a reference to a conditional second argument for the .remove() method. Should be easy enough to understand the use case for this one.

Third, lines 11, 36, 56, and 77 reference utilities.wrapNotesDocument(arguments[0]);. This is actually a use of the wrapNotesDocument() method of the utilities Object found in the "core.jss" SSJS library.

This method is a copy of this wrapDocument() SSJS function by Mariusz Jakubowski from OpenNTF.org XSnippets, and is an excellent example of how these methods should work.

Use Case: Conditional Validation and Error Reporting

Our time tracking example application will allow you to save a "draft" status punch notesDocument at any time, but we want to validate the punch for required fields when we change the status from "Draft" to "Submitted for Review".

Here's the pseudocode breaking down our conditional validation:

.submitForReview()

Check all required fields.

  • If "passed"...

    1. Change "status" field to "Pending Review".

    2. Save the "punch", and then open it in read mode.

  • If "failed"...

    1. Warn the user of the missing or malformed form data.

Now let's take a look at the punch.submitForReview() method:

The above method refers to several methods from my utilities object. As mentioned, these libraries can be created and expanded over time creating an evolving functional toolkit for your application development needs.

... but back to the above function specifically. The finally block will check to see if the rBoolean is true/false. If true - meaning it passed our validation - it will call the punch.submit() method... which itself returns a Boolean.

In other words, once we've validated the "punch", we try and save it. If it saves without an error, we open the "punch" in read mode.

Now let's look at the "Submit for Review" button that will sit at the top of our XPage "punch" form:

The onclick eventHandler is using a Partial Refresh so - in the event of a validation failure - we can simply paint the UI while maintaining the scoped data.

UI Validation Message for 'datepost' Field. UI Validation Message for 'datepost' Field.

If the validation passes, the punch.open() method is eventually called which uses a context.redirectToPage(), thus navigating the user away from the Partial Refresh'ed XPage to the read mode version of the updated "punch".

We included the punch.submit() and punch.open() methods in the punch.submitForReview() method as an example. Ideally we would return a Boolean for each of those methods and use those Booleans in a more task-oriented design.

So let's revisit our punch.submitForReview() method:

-- and now our "Submit for Review" button:

-- because if we do that, we can easily do this from a View XPage:

Conclusion

We've covered a lot in this primer, and we've only scratched the surface.

As mentioned, I have a library of core utility methods that have become my Go To methods when coding. For example, utilities.isEmpty() has replaced my null, [], "", NaN, and undefined checking. If I want to write a validation error to the screen or a simple "Hey, you did it!" message I use my utilities.addMessage() method.

The core library will grow. You may even - as I have - create a company-standard library that contains methods like tracking.updateHistory() for updating create/read/write/delete histories and standard.generateID() for creating a unique ID/key for a given record.

For enterprise application developers, it's critical to have easily managed and consistent code. While you can certainly do this without using the Object Literal syntax, this syntax allows for immediate code readability and recognition.

punch.open() is used to open a "punch".

employeeProfile.getPunches()... is used by the "employeeProfile.xsp" XPage to return a list (it's actually an object) containing all keyed "punch" records.

There are many reasons that I would recommend using this technique, but here's one you perhaps haven't considered:

Understanding the object literal syntax in a language that you're currently using [JavaScript, Server Side JavaScript] will allow you to more easily transition to object oriented programming like Java.


About the author: Chris Toohey

Thought Leadership, Web & Mobile Application Development, Solutions Integration, Technical Writing & Mentoring

A published developer and webmaster of dominoGuru.com, Chris Toohey specializes in platform application development, solutions integration, and evangelism of platform capabilities and best practices.



More from dominoGuru.com

dominoGuru.com is powered by IBM Notes Domino XPages & hosted by Prominic.NET

Contact Us

Use our Contact / Feedback form or one of these email addresses:

Creative Commons License

Except where otherwise noted, dominoGuru.com by Chris Toohey is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.