Whenever I’m working on a project that needs some sort of custom form field, I usually do my best to build it in a really modular way so that it can be reused. If it seems especially useful and I can imagine others enjoying it, I roll it into the great dumping ground we call DataObjectManager.

I’m not particularly proud of this, but it is a major benefit of having a huge install base for my work. It’s really easy to deploy useful things without asking you all to download new code from new places. As some of you may know, the “code” folder of DOM has already been segmented, somewhat logically, into submodules including dropdown fields, wysiwyg fields, and date fields. Today we’re welcoming to new members of the dropdown fields family — LiveDropdownField and FilteredDropdownSet.

LiveDropdownField

I was motivated to create this when I saw not only how taxing, but also how cumbersome SimpleTreeDropdownField was becoming. We love SimpleTreeDropdownField for the obvious benefits:

Working within a DOM popup (we shun the likes of TreeDropdownField for its marriage to the Prototype library)

Snappy response time (no AJAX calls)

But SimpleTreeDropdownField can become an enemy, given the right context. If you have 400 pages in your site tree, the database overhead is tremendous. Further, if you have really long page titles, the formatting gets really ugly. This is something we’ve worked on to some extent. Community members Dan Hensby and Marcus Dalgren in particular have been strong contributors to the improvement of SimpleTreeDropdownField.

Performance enhancements aside, SimpleTreeDropdownField can be a really frustrating way to locate a page when you have hundreds in your result set. LiveDropdownField allows you to perform an autocomplete search of the result set to find the page you’re looking for, and also comes with an option to expose the entire result set with one click. Here’s what it looks like right now:

FilteredDropdownSet

This widget is a little more complex, and much less likely to be used, if you ask me, but it’s come up a few times in my projects, so I figured it was time to bundle something up. Sometimes dropdown fields are sympathetic to each other, that is, the choices in one are dependent on the selected choice of one of its peers. Imagine that we’re choosing a product category and a product. Products have a CategoryID. A workflow might look like:

Choose a category (Fruit, Vegetable, Meat, Grain)

User chooses “Fruit”

A second dropdown, “Choose a product” is now populated with “Apples, Oranges, Pears”

Some of you data geeks might have picked up on the the redundancy of the ProductCategoryID field. After all, if a Product has one Category, and we know the product, don’t we inherently know the Category as well? Of course. It is absolutely redundant. But unfortunately, for this release, it’s a requirement in order to preserve the state of the dropdowns after saving.

An array of the dropdown fields to be included in the FieldGroup (inline display of form fields)

The field that is being filtered on the dropdown on the right (defaults to “ParentID”)

The data class for the objects being filtered (defaults to “SiteTree”)

In theory, the list of dropdowns can be infinitely long, provided the filtered field and data class are always the same, for instance, if you wanted to traverse the site tree using dropdowns. I’m not sure that’s a practical use of this field, but it would work. Most of the time, a pair of dropdowns will serve your needs.

These dropdown fields are not part of the scaffolding that comes out of the box. You’ll need to use a getCMSFields() function like you do with SiteTree objects, but just don’t call parent::getCMSFields().

I did have the new field in a getCMSFields() function. I’m not understanding what you mean when you say don’t call parent::getCMSFields(). If I take that out then what do I replace it with. $fields = ?what?

Hey, Andrew! Thanks for the feedback. Internal vs. external links are business logic that isn’t really in the scope of the form field. LiveDropdownField is just used to browse for related has_one objects. In this case, I used SiteTree as an example. In a real use case, you’d probably see two fields, one for internal (has_one) link, and one for external ($db) link. I’ll typically write a function like:

I’ve been trying to use FilteredDropdownSet and I’ve got it listing the categories and items correctly and the selection is saved correctly, but when editing, the dropdowns don’t select the saved item. I suppose it has to do with that AvailableProduct.php thing, but how exactly is the class and the has_ones in it supposed to be named?

Featured Posts

I’m very happy today to release a preview of a project I have been working on for several months under the working title “SilverSmith.” SilverSmith is a framework for building SilverStripe sites that provides code, template, and content generation tools using a YAML configuration file. I have been using this tool on several projects and it has saved me volumes of production time by cutting out all of the repetitive tasks involved in building a SilverStripe. I’m really excited to share it with the community and get some feedback.

One question that I find myself answering frequently for users of the EventCalendar module is how to customize the module to handle registrations. This guided tutorial will show you how to make a basic registration form with EventCalendar.

Fan of Uncle Cheese?

Help keep this blog going so I can continue to serve the SilverStripe community.