Extending Prototype to parse model ID from DOM ID

Posted on November 6th, 2008 2 Comments »

Consider a simple list of to-do tasks:

<ol class="tasks">
  <li id="task-1">run</li>
  <li id="task-2">vote</li>
  <li id="task-3">code</li>
</ol>

There are three task instances (with ids 1, 2, 3), each of which is rendered as a list element referenceable by DOM id. Note the id format: <model>-<id>, e.g. "task-1". This pattern is frequently used to avoid collisions with ids for other models because DOM ids are global and cannot be qualified to a particular object type or namespace (e.g. Task v. Group). When using the <model>-<id> format, you'll often want to obtain just the model id portion, say, to send to the server to edit or delete a task. After you've written code like this a few times:

var modelId = element.id.split('-').last();

you'll be overcome by a strong urge to extract a method that hides the ugly and standardizes the approach. I use the Prototype library at work, so I've implemented a utility method as an extension to Prototype's Element, making it available to any html element obtained via $() or $$(). However, the idea is easily implemented in jQuery or a library-agnostic manner. Here's the code:

/*
 * Prototype Element extensions
 */
Element.addMethods({
  /**
  * Returns last delimited portion of dom id for id or element passed where element id is of the form:
  *   example-<id> OR example_<id>
  * Supports hyphen '-' or underscore '_' as delimiter. Returns null if element id is missing or does not
  * contain a delimiter. Some example ids:
  *   task-group-25 // Returns 25
  *   25 // Returns null; use element.id instead
  */
  modelId: function(element) {
    var id = $(element).id;
    if (id == null) return null; // Just in case; browsers tested return empty string for missing id.	

    var idParts = id.split(/[-_]/g);
    return (idParts.length > 1) ? idParts.last() : null;
  }
});

/*
 * Usage
 */

// Get single task id
$('task-1').modelId(); // Returns "1"

// Get all task ids
$$('.tasks li').invoke('modelId'); // Returns ["1","2","3"]

Sometimes a String is just a String. Or not.

Posted on November 4th, 2008 1 Comment »

JavaScript, I love you, but I will never understand you. From the Firefox console:

>>> typeof 'test'
"string"

>>> 'test' instanceof String
false

>>> s = new String('test')
>>> typeof s
"object"

>>> s instanceof String
true

So the string "test" can be a "string", not a String, an "object" or a String. Good times. Then there's my personal favorite:

>>> typeof null
"object"

Null is an object? I object. In Ruby, nil is a full-blown object but in JavaScript, null is not. So when it comes to typeof, be careful what you ask for.

Douglas Crockford, perhaps the Godfather of JavaScript, comments further on typeof weirdness and offers an improved implementation.