dijit.form.ComboBox with complex drop-down menu

5.4k Views Asked by At

I'd like to create a more interesting blog autocomplete widget; one that will return a drop-down menu that will contain: (a) title, (b) keywords, (d) date. E.g.:

|======================
| inte|
|======================
| Interesting Title
| Tags: title, bar
| Date: Jun, 12 2010
|----------------------
| Interner Guide 
| Tags: guide
| Date: Aug, 12 2010
|----------------------
|          ...
|======================

I. First Option

One way of achieving this is by overriding the _createOption of the _ComboBoxMenu like this:

dojo.declare("SearchBox", dijit.form.ComboBox, {
    postMixInProperties: function() {
        this._popupWidget = new SearchBoxMenu();
        this.inherited(arguments);
    }
});

dojo.declare("SearchBoxMenu", dijit.form._ComboBoxMenu, {
    _createOption: function(item, labelFunc) {
        var menuitem = dojo.doc.createElement("li");
        menuitem.innerHTML = [
            "<ul>",
                "<li>", store.getValue(item, "title"), "</li>",
                "<li>Tags: ", store.getValue(item, "tags"), "</li>",
                "<li>Date: ", store.getValue(item, "date"), "</li>"
            "</ul>"
        ].join("")
        return menuitem;
    }
});

But I'm (a) overriding a private class, then (b) it's private method, so if the method signature changes for these classes in dojo 1.6 -- I'll be in trouble. This makes this way a bit undesirable.

II. Second Option

The second way will not break if the private API signature changes, but does mix data with presentation:

var myStore = new dojo.data.ItemFileReadStore({
    data: {
        identifier: "title",
        items:  [
            {title: "Interesting Title",
             tags: "title, bar",
             date: "Jun, 12 2010",
             label: "<ul><li>Interesting Title</li>"
                 + "<li>Tags: title, bar</li>"
                 + "<li>Date: Jun, 12 2010</li></ul>"}
        ]
    }
});

var box = new dijit.form.ComboBox({
    store: myStore,
    searchAttr: "title",
    labelAttr: "label",
    labelType: "html"
}, "ipt1"),

The labelAttr tells the ComboBox to look at the dataStore's items[].label and use that in the drop-down menu. The "labelType" tells the _ComboBoxMenu to include it as HTML instead of as a simple string. As I've mentioned above, one disadvantage of this method is that it mixes data with presentation.

Question: Thus, I have two options, but neither is perfect. Is there a better way? If not -- which one do you recommend?

2

There are 2 best solutions below

0
On BEST ANSWER

The answer was described in the Rich Text Test on the "autoComplete" test page: http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/_autoComplete.html#richtextest.

The only thing that makes me feel a bit better is that I've tried this solution before, and it didn't work with dojo 1.5. It does work on the nightlies and, hopefully, with all subsequent stable builds. It's a combination of option 2 and a label-view function:

var myStore = new dojo.data.ItemFileReadStore({
  data: {
        identifier: "title",
        items:  [
            {title: "Interesting Title",
             tags: "title, bar",
             date: "Jun, 12 2010"}
        ]
    }
});

var box = new dijit.form.ComboBox({
    autoComplete: false,
    selectOnClick: true,
    store: myStore,
    searchAttr: "title",
    labelType: "html",
    labelFunc: function(item, store) {
        return [
            "<ul>",
                "<li>", store.getValue(item, "title"), "</li>",
                "<li>Tags:", store.getValue(item, "tags"), "</li>",
                "<li>Date:", store.getValue(item, "date"), "</li>",
            "</ul>"
        ].join("")
    }
}, "ipt1");
1
On

I don't think there is a better way.

Personally I'd go for option 1 and keep a record of all the private APIs you're using and should check for on upgrade. Better yet, provide a patch for hooking in your own popup widget and submit it, making sure the next version has the change you want to see in it :)