Wednesday, July 28, 2010

Using string-based property accessors in javascript

When it comes to javascript development, I rely heavily on using plain javascript objects for data, often loading JSON data from an async server call. Below is some typical JSON that I might load after it has been processed into a plain javascript object. Note that the loaded data contains an array of users along with extra data is used for pagination purposes (count, page, and max).

When using this data, I typically directly access the properties in these objects. I'm not sure if there is a recognized name for doing this, but I'm going to call it direct property access. And I'd say that in many cases, this is the best solution for the job. Here's an example of direct property access:

However, as the complexity of my applications have increased, I've found many situations where using direct property access becomes cumbersome. For these situations, I've been exploring the use of what I'll call string-based property access. I'm finding that there are real use cases where doing it makes sense.

Use Case #1

I need to find a deeply nested property value in an object. But there is a chance that some of the properties in the path could be undefined. I want simple code to access this property if it exists, and not some large chunk of code with many tests along the way for undefined values. And I want to specify a default value if anything in the path is undefined. Compare this:

To this (and then imagine something many levels deep):

Using string-based property access seems to be the more elegant solution, especially when you are dealing with many levels in depth. It avoids littering your code with lots of excess code. In my situation, I'd rather have my overall JS download size be smaller and put a little extra processing onto the client.

I found a very basic resolve implementation but am not currently using it. Note that it doesn't handle anything besides dot separators (no arrays, etc.), and it doesn't have the 3rd default value as an option.

There is also a large and flame-filled discussion about the best way to do string-based property access on comp.lang.javascript. This conversation gets into handling arrays, array-like property access, and so forth. But for many scenarios, handling just simple dot notation might be good enough.

Use Case #2

I want to localize my application, so I've defined a JS object as a lookup table of strings. I want to insert values from my database into these strings, but might put them in different locations depending upon the language. Here's an example lookup table:

Take a look at my StackOverflow question for some ideas on how to solve this. Again, the most elegant solution seems to be using string-based property access.

Use Case #3

I want the custom UI components in my application to all access data in the same manner. Each component would have a wrapper object around my actual data object (which I call a Model). Each component would know how to get data from a Model, and the Model would know how to grab my data (from an internal JS object, an HTML5 store, from a remote JSON call, etc.). When my components are created, the data doesn't necessarily have to exist first, and could be loaded as a different part of the lifecycle.

This is the way that the Apache Wicket framework does things, and I believe that it is the right solution for the problem. Even though it is for Java, there are some very good reasons to look to it for ideas and inspiration. Wicket's PropertyModel (extends Model) object uses string based property accessors very effectively.

Wicket uses Models and PropertyModels as wrappers around your POJOs. This enables the framework to have a consistent interface when dealing with data objects, as it simply needs to know how to work with a Model instead of each specific POJO. It also provides a means to detach POJOs from the models and then reattach as necessary. The solution works really well, but relies on string-based property accessors.

In addition, Wicket's CompoundPropertyModel concept could be utilized in a javascript application. That would really help simplify my component/client code and offload the data access into reusable objects. Even if you aren't a Java programmer or hate Java, many concepts introduced by Wicket are worth considering, especially the component-based nature of the framework and the way it wraps Models around data.


At this time, I don't have fully implemented string-based property access method in place yet. I'm currently using a combination of methods to see what works best. I'm leaning toward going with a simpler solution that doesn't catch all possible strings and just handles dot notation in the strings. But before I commit to this, I'm going to play with it some more to see if anything comes up where I might need a more robust solution.

If anyone has thoughts on any of this, or links to other resources I should look at, I'm all ears!

No comments: