Titanium Mobile – Extending Views with CommonJS

When you’re building an intricate user interface with Titanium Mobile, you’ll absolutely want to organize your UI elements into well-designed CommonJS modules. This makes it easy to reuse components throughout your app and even across other apps. It’s also a lot easier for maintainers to deal with it if you organize it well.

What if you want to build a class that represents a specialized Window with a set of controls for performing a special task? You might like to subclass Ti.UI.Window. The problem you will quickly discover is that Titanium views are all proxy objects for their corresponding UI elements on the mobile platform. So you can’t inherit with the prototype property like you might expect to do with other "regular" Javascript objects.

I have seen two good approaches for this: building a wrapper class the Ti proxy object with a regular javascript object, and using parasitic inheritance to extend the proxy object.

Wrapper classes

Note that if your window takes additional parameters beyond those accepted by the Ti.UI.Window, you will likely need to process those parameters before you pass them to the Ti.UI.createWindow() call. Let’s get a bit more specific here. Imagine we have a window that is designed to show a particular image with a full-window ImageView. When we construct the object, we can pass any of the valid Window parameters to it, plus a new parameter, "imageurl", which contains the URL of the image we want to display.

Notice how we look for the imageurl parameter in the params object; if we find it, we set our private property _imageurl, and then we remove it from the params object before we use it to create the Window object.

OK — we now have a fairly interesting class. But if we want to open the window from our app.js class, how can we do it? We have to implement a method that lets a caller access the _proxy Window object. I don’t like this part of it, because it makes our class decidedly unlike a real Window object, requiring the caller to know about this special accessor function. But here’s how we could do it:

In our caller, we do this:

Another approach would be to add a "passthrough" method, open(), that in turn calls _proxy.open (). But that poses a number of problems, most notably, the fact that you don’t always open windows the same way (if your app uses a TabGroup, for example, the way in which you open windows is different on iOS and android).

Pros

This technique is somewhat less risky than the parasitic inheritance approach, as it avoids the possibility of method collisions for setters and getters on iOS (see below).

Cons

This technique requires that you write passthrough methods or expose the wrapped proxy object to callers. Either way, the caller can’t treat the object as a real Ti.UI.View in all situations (even if you had a passthrough method for every single method in the proxy class, you’d still have issues with properties, for example).

Parasitic inheritance

Parasitic inheritance is where we use the flexibility of Javascript’s constructor mechanism to co-opt another object, add properties to it, and return it from our constructor. It helps to understand the basics of the javascript new operator.

Take this simple example of a constructor:

The new operator instantiates an object (inherited from Foo.prototype), calls the function Foo(), binds the new object to "this", and uses the return value from Foo() as the result of the new expression. If no value is returned from Foo(), the newly created object is used as the result of the expression. (more on this: https://developer.mozilla.org/en/JavaScript/Reference/Operators/new)

Typical constructors do not return objects; they just operate on the this variable. When we employ parasitic inheritance, the constructor does return an object.

Let’s look at how we might do that with our MyWindow class:

Now look at the caller code:

Now the caller is treating the MyWindow as a real Ti.UI.Window, which is very convenient.

It’s interesting to note that the MyWindow() constructor function never references this. So in fact, the new operator isn’t really doing anything here. You could drop it: That doesn’t read as naturally for developers used to other OO languages, so I like to leave the new operator in there, even though it’s actually wasteful to create an object that never gets used. This brings up an interesting point. If your parasitic inheritance constructor is to return null under some circumstances (for example, the user forgets some critical parameter in the constructor call), you should omit the new operator; when your constructor returns null, new will use the object that it instantiated instead of the return value!

Finally, it’s good to note that you can add functions to the proxy object:

Now you can do this in the caller:

Pretty slick.

There is an important caveat: Never start a function name with "set" or "get". These will conflict with mechanisms in the iOS that handle proxy object properties, and your functions will not work on iOS. I’ve even heard that you should avoid functions that start with "init". I am not sure about that one, but I avoid it anyway.

Overriding methods

Unfortunately, you cannot override the methods of the proxy objects. If you need to change the behavior of an existing method, you’ll have to create a new method. This puts you in the situation where the caller has to know about this new method, similar to our wrapper class. There is a fascinating discussion on this topic at http://developer.appcelerator.com/question/112471/javascript-inheritance-with-mobile-api-objects

Pros

With this technique, the caller can treat the objects of your class as genuine Ti.UI.View objects, which is very convenient.

Cons

There is a risk of method name conflicts on iOS (see above), but it’s easy to avoid.

Summary

I find that most of the time I like the parasitic inheritance approach. I think it keeps the interfaces to my classes consistent with the Ti.UI.View objects, which makes it somewhat easier to read; you don’t have to think too much about whether you’re dealing with one of our custom classes or a base view class.

In fact, the Titanium developers used parasitic inheritance in their template applications, so it must be a reasonable approach.

I like to name my proxy object _self so it’s very clear which view object is the one that is being returned by the constructor.

Back to Titanium Mobile: Beyond the prototype

Leave a Reply

Your email address will not be published. Required fields are marked *