329 Lotus blogs updated hourly. Who will post next? Home | Downloads | Events | Jobs | Twitter | Bookmarks | Pods | Blogs | Search | myPL | About 
 
Latest 7 Posts
locating XPage components with XspQuery
Sun, Apr 14th 2013 246
your how is not your what
Wed, Apr 3rd 2013 356
Developer2013 and IamLUG
Mon, Apr 1st 2013 194
my new favorite quote
Sat, Mar 23rd 2013 327
Taking the scary out of Java in XPages: fixing the API
Thu, Mar 21st 2013 236
Taking the scary out of Java in XPages: knowing the entry points
Sat, Mar 2nd 2013 408
Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 346
Top 10
I have seen the future, and it is phabulous
Sat, Dec 8th 2012 674
SSJS is a crutch
Fri, Feb 22nd 2013 669
the next step in the journey
Wed, Jan 9th 2013 642
org.openntf.xsp.extlib
Mon, Jan 21st 2013 526
Needle in the Stack Part 2: talk to data, not to components
Thu, Jan 17th 2013 424
Passthru vs. component - my perspective
Sat, Feb 16th 2013 412
Taking the scary out of Java in XPages: knowing the entry points
Sat, Mar 2nd 2013 408
your how is not your what
Wed, Apr 3rd 2013 356
Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 346
fasten your seat belt, Dorothy
Thu, Oct 11th 2012 334


inheritance library for client- and server-side JavaScript
Tim Tripcony    

A topic that periodically resurfaces surrounding XPage development is the notion of creating "classes" in JavaScript. There are several schools of thought - not just in our own community, but across the entire web development spectrum - regarding how best to handle inheritance in JavaScript, because the language itself is not classical... it is prototypal.
 
In nearly every other language, we define a class and then create objects that are instances of that class. With JavaScript, however, there is no need to define two separate structures: we can just define an object that has the behavior we need and use it. If we need something that extends that object's behavior, we can create a new object, link its prototype to the existing object, then add the new behavior. Trying to squeeze the language into our own narrow comfort zone robs the language of its flexibility and power, and ourselves and our users of the kind of functionality we could be creating for them.
 
More to the point for XPages, perhaps, is that if we're planning on creating deep classical hierarchies at runtime, it's likely that we've identified a need to do so either because the functionality we plan to implement will be complex, we want our code to be reusable, or both. While JavaScript is perfectly capable of doing complex things, when we're doing complex things in SSJS, we're interacting with Java API's, whether that be the core Domino API or other third party libraries; we're using Java classes, even if we aren't creating any of our own. To put it another way, SSJS is just an entry point to Java, so we can either hang out in that foyer all night... or venture inside and join the rest of the party.
 
That said, I understand that many XPage developers are nervous about taking that leap; I understand: I've been there myself. In the meantime, I'd like to offer some code that may help to soften the landing: a single-function library that allows you to easily structure your JavaScript code into reusable, extensible, class-like objects.
 
 Before we actually dig into that function, let's take a look at a very basic example of a class you might create:

  1. function Person(config){
  2.  var person = Base.extend({
  3.   getFirstName: function(){
  4.    return config.firstName;
  5.   },
  6.   getLastName: function(){
  7.    return config.lastName;
  8.   },
  9.   getFullName: function(){
  10.    return config.firstName, config.lastName.join(" ");
  11.   },
  12.   toString: function(){
  13.    return person.getClassName(), person.getFullName().join("n");
  14.   }
  15.  },Person);
  16.  return person;
  17. };

 
To "instantiate" this class, we simply call the Person function, and pass it a config object that bundles all of our constructor arguments into one:

  1. var me = Person({
  2.  firstName: "Tim",
  3.  lastName: "Tripcony"
  4. });

There are a couple things happening here that might be of interest. The first is that, since all information about the object to be created is passed as an object, the order in which the properties are specified is irrelevant; there is no need to remember whether you're supposed to pass firstName first and lastName last... in point of fact, since you're naming the properties when you pass them, someone maintaining your code can actually see what's happening without having to dig through the code that you're calling in the hopes of guessing what each argument means. Sure, it's a few extra characters to type at each instantiation, but it'll save you minutes or even hours when you come back to the code later to fix or enhance it.
 
The second atypical characteristic of this pattern is the absence of the keyword "new". Unlike typical inheritance patterns in JavaScript, which require the use of new to avoid having the global object clobbered by the constructor function, this pattern makes new optional; if the code were instead "var me = new Person(...", the runtime result would be the same. Hence, if you feel that including it makes your code more readable by telegraphing that you're creating a new instance of a Person object, you're welcome to do so. But it's entirely optional... your code won't break if you decided you were going to use new and then forgot to.
 
One of the core characteristics of a classical inheritance model is the ability to define "private" information: properties and methods that can be accessed by code internal to the class but not from outside of it. Let's take a look now at an extension to the Person class that includes private information: 

  1. function Employee(config){
  2.  var employmentStatus = "Active"; // "private" variable attached via closure
  3.  var employee = Person(config).extend({
  4.   fire: function(){
  5.    employmentStatus = "Terminated";
  6.   },
  7.   getId: function(){
  8.    return config.employeeId
  9.   },
  10.   getStatus: function(){
  11.    return employmentStatus;
  12.   },
  13.   rehire: function(){
  14.    employmentStatus = "Active";
  15.   },
  16.   toString: function(){
  17.    return employee.getFullName(), employee.getId(), employee.getStatus().join("n");
  18.   }
  19.  },Employee);
  20.  return employee;
  21. };

Because this class extends Person, instead of calling Base.extend, we pass the config argument to the Person constructor, and then call .extend() on the result. In a deep hierarchy, a single object flows through multiple constructors, each customizing it to add the behaviors that it defines, and returning the customized result. This allows each class definition to have minimal code, making your library as a whole more maintainable.

This constructor defines two variables: the employee object that we will actually return, and employmentStatus, which at first glance looks like a throwaway variable because the constructor function finishes before we get a chance to do anything to it. But because we returned something from the function, as long as the object we returned is alive, any other variables that were defined within the same function as that object still exist... but only that object can get to them.
 
If you've ever heard the term "closure" in connection to JavaScript, this behavior is what that term refers to: employee and employmentStatus are defined inside the same function, and we return employee from that function, so as long as something, somewhere in our code still has a valid handle on the employee object, employee's methods can access - and change - the value of employmentStatus, but nothing else can. Ergo, employmentStatus is a private property of our Employee class.
 
Why does all this matter? If the only thing that the fire() and rehire() methods do is change the value of employmentStatus, why not just make that property public? Because, unlike this example code, in a real application, firing an employee is a complicated affair. There are systems that the employee needs to be locked out of, payroll needs to be notified to stop sending a paycheck, and so forth. You can't just set an employee's status to "Terminated" and leave it at that. Keeping this field private ensures that, if a call to getStatus() used to return "Active" and now it returns "Terminated", at some point in between a method was called that had an opportunity to do other things before it changed that value.
 
Now let's extend Employee by creating another descendant class: 

  1. var Developer = function Developer(config){
  2.  var developer = Employee(config).extend({
  3.   setSpecialty: function(newSpecialty){
  4.    config.specialty = newSpecialty;
  5.   },
  6.   getSpecialty: function(){
  7.    return config.specialty;
  8.   },
  9.   toString: function(){
  10.    return
  11.     developer.toString.ancestor(),
  12.     developer.getSpecialty()
  13.    .join("n");
  14.   }
  15.  },Developer);
  16.  return developer;
  17. };

As before with the Employee class, we only need to add what's different at this layer. Developer will automatically support getStatus(), because a Developer is an Employee; we don't need to specify that again here. Similarly, Developer will support getFirstName(), because a Developer is an Employee, and an Employee is a Person. We are, however, choosing to override toString(). This is fully optional, but it often makes sense to include a way to retrieve a full text-based description of the object's state in a single method, and in both the Java and JavaScript world, the convention is to call that method toString().
 
In particular, check out line 11 of the above example class. Often when overriding a method in a parent class, the parent's definition of that method is already doing most of the work that we need done, but not all (otherwise we wouldn't be overriding it to being with, we'd just inherit it). In Java, any method of a child class (e.g. Developer) can refer to "super" to get a handle on the current object as an instance of its parent class (e.g. Employee). This isn't actually another object, it's just a temporary reclassification (in Java terminology, "cast") of the object we're already in. So we can call super.toString(), and it will execute the toString() method as it's defined in the parent class, but run it against the current object. Implementation of that pattern gets a bit messy in JavaScript, so this library takes a slightly different approach.
 
In JavaScript, functions are objects. So, just like a function can be a method of a larger object, functions themselves can have methods (and properties). This library takes advantage of that by giving each overridden method a method of its own; because "super" is a reserved word in JavaScript (although the language doesn't actually use it), the method is called "ancestor" instead. So in the above example, the Developer implementation of toString() includes a reference to developer.toString.ancestor(). Because this is a strange pattern, let's do a split on the period and analyze this expression in three parts:
  1. developer - refers to the object that will be returned. We could just use "this" instead, but "this" is surprisingly volatile in JavaScript; by naming the object we'll return ("var developer = Employee(config)..."), we can refer to it by its name inside the object itself, which ensures that we're always referring to that object, even if something bizarre happens that causes the scope of "this" to change at runtime.
  2. toString - gives us a handle on the toString method of the developer object. Because we're not appending parentheses to this handle, it does not run the method, just provides a handle to the actual function object (as opposed to the result of its execution). This is crucial, because we're obtaining this handle inside the method that this handle points to, which is already weird enough, but calling the method inside the method would cause recursion. Recursion is a powerful thing when done right, but that's not what we want here. We simply want the method we're already in to be able to get a handle on itself - not to run it again, but to retrieve one of its own members.
  3. ancestor() - gives us a handle on the method we're already in, but as it's defined in the parent class, and then executes it against the current object instance.
In short, this one line of code is yet another example of letting the parent class do the work for us, where appropriate. We let the ancestor method glean most of the information that's being requested, then tack on the one extra bit that it doesn't have access to.
 
Before we wrap this up, let's change our example object to be an instance of the Developer class: 

  1. var me = Developer< span class="br0">({
  2.  firstName: "Tim",
  3.  lastName: "Tripcony",
  4.  employeeId: "OU812",
  5.  specialty: "XPages"
  6. });

So we've only added a couple properties to the config object we're passing to the constructor, but the resulting object is capable of much more specialized behavior than it was when it was just an instance of Person. And yet, to customize what this object can do, we need only modify the class where the change is appropriate, and that change will filter down to all instances of any class that inherits from the class that we changed. That is ultimately what makes object-oriented programming so powerful.
 
One last thing: every object created using this pattern supports two additional methods: getClassName() and instanceOf(). In our final example, the former will return "Person.Employee.Developer" if the code is running client-side in Firefox; function.name is not part of the official JavaScript spec, so in SSJS and most browsers, getClassName() will return "..". I know, not terribly useful. The instanceOf() method is another example where the behavior differs: in Firefox, you can pass it either a handle on the constructor function or its name (e.g. me.instanceOf("Person") === me.instanceOf(Person)); it returns true if the object was created using either the specified constructor or any of its ancestors. In SSJS and most browsers, however, the argument must be a real handle on the constructor... passing it the name doesn't work - again, because in those contexts functions don't have a .name property. And yes, for the JavaScript ninjas among you, I already tried using arguments.callee.caller; that's not standard either.
 
Finally, here is the library that makes this pattern of code reuse possible. And, to give credit where credit is due, the code of this library was inspired by techniques used by Douglas CrockfordDean Edwards, and John Resig. Hopefully all of you already know who they are and consume any content that they produce. If not, now would be an excellent time to start.


---------------------
http://xmage.gbs.com/blog.nsf/d6plinks/TTRY-8ABUMC
Oct 18, 2010
172 hits



Recent Blog Posts
246


locating XPage components with XspQuery
Sun, Apr 14th 2013 12:00a   Tim Tripcony
Several years ago, I wrote a utility Java class designed to make it easy to search for components within the current XPage instance based on various criteria. I've found it enormously useful, and, apparently, so has Keith Strickland, because he added it to org.openntf.xsp.extlib, complete with a few refinements. As an example of how you might use this, examine the following line of code: List requiredFields = new XspQuery() .addInstanceOf(UIInput.class) .addEquals("required", true) .loc [read] Keywords: ldd lotus dojo java javascript openntf oracle server
356


your how is not your what
Wed, Apr 3rd 2013 11:36a   Tim Tripcony
I've noticed a pattern emerging when I'm asked for help with XPages. Here's a representative conversation: "I'm trying to do [X] and it's not working. How can I do that?" "What are you trying to accomplish?" "I already told you. I'm trying to do [X]." "No, that's how you're trying to do it. What are you trying to do?" For example, replace "[X]" with "reach into a repeat control from outside it" (since this has become the most frequent topic I'm asked about [read] Keywords: xpages application
194


Developer2013 and IamLUG
Mon, Apr 1st 2013 7:33a   Tim Tripcony
I will be presenting at two upcoming conferences, Developer2013 and IamLUG. Developer2013 will be held at the MGM Grand in Las Vegas April 30 to May 2, and is organized by THE VIEW. I will be presenting the following sessions: Doing more with less code in XPages "Work smarter, not harder." We're all expected to, but are rarely told how. In XPages, however, we have many opportunities to do precisely that. This session will equip you with techniques for writing less code to achieve th [read] Keywords: domino lotus notes notes client xpages application applications desktop development facebook interface laptop linkedin mobile twitter
327


my new favorite quote
Sat, Mar 23rd 2013 5:20p   Tim Tripcony
"We go about our daily lives understanding almost nothing of the world. We give little thought to the machinery that generates the sunlight that makes life possible, to the gravity that glues us to an earth that would otherwise send us spinning off into space, or the atoms of which we are made and on whose stability we fundamentally depend. Except for children (who don’t know enough not to ask the important questions), few of us spend much time wondering why nature is the way it is; where the [read] Keywords: wiki
236


Taking the scary out of Java in XPages: fixing the API
Thu, Mar 21st 2013 4:00a   Tim Tripcony
Suppose you had a motivation to learn a new spoken language. As an example, let's imagine that you live in the U.S., but your job requires you to occasionally visit Paris, so you've decided to learn French. But you're not planning to move there, just spend a week there every couple months. So you don't want to learn the entire language, just enough to facilitate basic interaction whenever you're there. So you briefly considered taking a semester-long course at a local community college, but [read] Keywords: domino ibm lotus lotusscript notes xpages application best practice community css database google java openntf oracle twitter wiki
408


Taking the scary out of Java in XPages: knowing the entry points
Sat, Mar 2nd 2013 3:02a   Tim Tripcony
Before we dive in to this first topic, I should mention Declan's series, "XPage Java Roots". Declan has been shifting more of his code to Java, so just as he did with his epic "Learning XPages" series, where he documented his initial experiences with XPages itself, he is now documenting his experience of learning how to take advantage of Java in XPage development. It's a safe bet that this series will be a very useful reference, so whether or not my own perspective on this topic prov [read] Keywords: admin agent domino ibm lotus lotusscript notes script library xpages application applications database development eclipse interface java javascript oracle server wiki xml




346


Taking the scary out of Java in XPages: Prologue
Tue, Feb 26th 2013 9:50p   Tim Tripcony
The discussion following my last post made stark the need for greater availability of information that makes the nature of Java more accessible to Domino developers. Credit for the title of this post goes to Declan, who is considering writing a series of blog posts on this topic. I will be doing the same; hopefully there will be a fair amount of duplication. As David Leedy is fond of stating, it's a good thing when several people share the same information, because that makes it easier for the [read] Keywords: domino xpages application java
669


SSJS is a crutch
Fri, Feb 22nd 2013 10:50p   Tim Tripcony
I've been debating for quite a while whether I should write this post. It obviously makes a potentially controversial statement. A fellow developer who knew I was drafting it put my hesitance into perspective: "you really want to be that guy?" This was my response: I want to be the guy who saves people pain. But sometimes to do that, you have to tell your friend if she wants to stop being punched in the face, she needs to leave the guy who keeps punching her in the face. This post is ju [read] Keywords: agent domino formula language ibm lotus lotusscript notes xpages applications development java javascript openntf wiki
412


Passthru vs. component - my perspective
Sat, Feb 16th 2013 9:40p   Tim Tripcony
Paul Withers posted a thorough article explaining the differences between namespaced XPage components (e.g. ) and their corresponding passthru elements (e.g. ), providing numerous examples of what actually happens when these objects are constructed. I've always heard (and often repeated) that passthru elements are more efficiently processed than their namespaced equivalents, so Paul's post inspired me to offer my own perspective. Simply put, there's practically no difference... but there a [read] Keywords: acl domino xpages application development properties security
526


org.openntf.xsp.extlib
Mon, Jan 21st 2013 5:20a   Tim Tripcony
About 18 months ago, I created an OpenNTF project called Community Control Library. The fundamental reason for creating the project was my belief that the single factor keeping the Domino community from realizing the true potential of the platform is the assumption that the XPages Extension Library is the extension library, not an extension library. Let's briefly revisit its history: IBM starts an internal project, code named "Porus" (in reference to the Greek / Roman god of plenty), inte [read] Keywords: domino ibm notes policies xpages application applications best practice community development openntf wiki




Created and Maintained by Yancy Lent - About - Blog Submission - Suggestions - Change Log - Blog Widget - Advertising - Mobile Edition