Hierarchical Select 2: the developer perspective

published on March 3, 2008

API

The API of the previous version of HS was a beast. Well, not the API, but the implementations. This has been fixed in version 2 of HS: it’s now much more elegant and much easier. If you don’t have to alter any forms, you can easily implement all hooks in less than a hundred lines, probably even less. The content_taxonomy implementation for example, is about 75 lines if you don’t count the form altering. That should make HS much more attractive to other Drupal developers.

Support Hierarchical Select Dynamically

One of the low-hanging fruits is to support HS dynamically (i.e. use hierarchical select form items when HS is installed, use normal selects otherwise).

If your module provides its own hierarchical structure for which you want to use HS, you’ll have to implement the hooks. Next, I assume you have something like this in your form:

$form['something'] = array(
  '#title'          => t('Select something!'),
  '#type'           => 'select',
  '#options'        => mymodule_get_options($some_param),
  '#default_value'  => variable_get('mymodule_something', 0),
);

To support HS dynamically, you’ll want to change it to something like this (consult API.txt for more details):

$form['something'] = array(
  '#title'          => t('Select something!'),
  '#type'           => (module_exists('hierarchical_select')) ? 'hierarchical_select' : 'select',
  '#options'        => mymodule_get_options($some_param),
  '#default_value'  => variable_get('mymodule_something', 0),
  '#hierarchical_select_settings' => array(
    'module'          => 'mymodule',
    'enforce_deepest' => TRUE,
    'save_lineage'    => TRUE,
    'params' => array(
      'someparam' => $some_param,
    ),
  ),
);

When the HS module is not installed, you can still safely add the #hierarchical_select_settings property, because the procesing code for the select form element will simply ignore the extra property.

Difficulties

In this section, I explain some of the difficulties faced in the implementation. This would (should?) interest you if you were looking to develop something similar: it should discourage you to roll your own, but to contribute or sponsor instead. Lots of tricky things have been solved for you!
If you’re not interested in this, you can just skip it.

Drupal’s Taxonomy module is of course the primary goal. But Taxonomy stores the terms “flat” (no hierarchy metadata) in the database, and that’s perfectly fine: I think pretty much every module that works with hierarchies does it this way.That’s perfectly fine, because you can reconstruct the hierarchy. Of course, I had to do this in a generic way, which makes it somewhat more difficult. Anyway: you won’t have to worry about this at all. Simply implementing the required hooks will be sufficient.

The amount JS code for this module has grown significantly: from 127 lines for version 1.4 to 417 for version 2.0. That’s mostly because of the other major new feature of HS 2: multiple select support. In version 1.x, there really was only one kind of callback: the one to refresh the current hierarchical select (lower case, because now I’m referring to the actual form element, not the module). Now, I have to support the “add to dropbox” and “remove from dropbox” events as well.

There are plenty of tricky consequences due to multiple select support. One example: as soon as you have at least one item selected, “” should be selected by default in the hierarchical select, to indicate that the user has already selected something. Another example: when a selection is being removed from the dropbox, you have to make sure that you keep all item ids except for the item id of the deepest item in the selection that’s being removed. The reason: in case of an acyclic directed graph (if you don’t know what that is: this is fancy terminology for the “multiple parents” setting for a vocabulary of the Taxonomy module), the same term id is potentially present multiple times. If you don’t ensure that it’s absent from the set of selected item ids, you’ll get the same hierarchy as before the removal when you’re reconstructing the hierarchy. If you felt as this was above your head, see this issue for clarification.

One of the most ugly things in HS is definitely the passing around of various settings: I have to store most settings for each hierarchical select somewhere in Drupal.settings.hierarchical_select, so the JS can access it. The JS needs it because it needs to pass it back to the server. I will be able to remove this altogether in the Drupal 6 version, thanks to $form_state.

Comments