12
votes

I've got a pretty simple problem whose solution turns out not to be that simple at all.
I want to add images in front of each option of a selectfield. To be more accurate, I want to add images to the picker it triggers, and also to the selectfield's current value.
For the sake of simplicity, I'll create a little example:

Let's say, you want a user to choose between one of the four playing card suits Diamonds, Hearts, Spades and Clubs. To support visual recognition, you want to prepend the corresponding symbol to each suit name, so it could look something like this:
Selectfield with icons

My first choice of a sencha touch component, that enables selecting from a given set of options naturally was selectfield. Unfortunately, it only seems to be able to display pure text, and nothing more. After digging into the sencha touch sources, I finally came up with half a solution. Basically, I pass the selectfield a custom defaultPhonePickerConfig, in which the corresponding picker(that is used by the selectfield to display the options) gets assigned a custom itemTpl. The itemTpl does the rest, namely adding some html to display the image:

defaultPhonePickerConfig: {
    listeners: {
        initialize: function() {
            var slots = this.query('pickerslot');
            Ext.each(slots, function(slot) {
                slot.setItemTpl('<img src="someImage.jpg"> {text}');
            });

        },

        change: function() {
            // reconstruct the selectfield's change handler,
            // since it gets overwritten
            var iconSelect = Ext.Viewport.query('#IconSelect')[0];
            iconSelect.onPickerChange.apply(iconSelect, arguments);
        }
    }
}

A working fiddle for this solution can be found here.

My solution isn't that bad, but there's a slight cosmetical problem, that's just not acceptable to me: The icons are only displayed in the picker (lower part of the screenshot above), but not the selectfield itself (upper, grayed out part) when the option was selected. And there seems to be no good way to add an icon to the selectfield's current value aswell.

And that's the main concern of my question: What good way is there to add an icon to both the picker's options and also to the selecfield's current value? Do I maybe just have to add relatively little code to my existing solution or should I take a whole nother approach?
Every contribution is appreciated. Thank you!

Update:
After some hacking around, I found a way (an ugly one) to prepend an icon to the selectfield itself. It is mostly based on brutal HTML DOM manipulation: I now also define event handlers for the selectfield itself (change and painted). On initialization and every time the value is changed, my handlers search the generated DOM for the underlying <input> and mess around with it. (That bad boy is probably the reason why we can't assign HTML in the first place, since the framework changes its value attribute. And value on the other hand can only contain plain text.)
This is how I define the selectfield's listeners:

listeners: {
       change: function () {
           var pickerDOM = document.querySelector('#' + this.getId() + ' input[name="picker"]');
           PickerIcons.app.prependIconToSelectfield(arguments[1], pickerDOM);
       },
       painted: function () {
           // Initialize an icon on creation
           var pickerDOM = document.querySelector('#' + this.getId() + ' input[name="picker"]');
           PickerIcons.app.prependIconToSelectfield(this.getValue(), pickerDOM);
       }
}

The corresponding function prependIconToSelectfield() just defines some CSS:

prependIconToSelectfield: function (optValue, domElement) {
    var iconUrl = this.getIconUrl(optValue);
    domElement.style.backgroundImage = 'url(' + iconUrl + ')';
    domElement.style.backgroundSize = '20px 20px';
    domElement.style.backgroundRepeat = 'no-repeat';
    domElement.style.backgroundPosition = 'left center';
    domElement.style.paddingLeft = '30px';
}

Check out this fiddle for a working example.

This is still no good solution to me, since doing this kind of hackish DOM manipulation is way too rogue for my taste. I don't know what the side effects of actively messing around in the DOM could be in bigger projects, and don't want to learn it the hard way. So, I'm still looking for a cleaner solution.

1

1 Answers

3
votes

First kudos on working so hard sencha touch is extremely hard to manipulate when you try to do something out of the box. Having said that let me try & propose a solution for what you want. A selectfield in sencha has the following DOM tag structure.

div.x-field-select
    div.x-field-input
        input.x-input-el
        div.x-clear-icon
        div.x-field-mask

Now concentrate on the x-clear-icon it is normally hidden since a selectfield does not need a clear button. First write a css class for it to show it(display: block). This would display it with an X button similar to text field & it will be positioned towards the right corner. You can through css position it to the left and on change of the select field you can change its background to what you want. It is not a very straight forward solution but i have tried it for a similar problem & it works. Judging from what you have done above i think you can do it. All the best. Hope my solution helps.