views:

1953

answers:

5

I have an ext combobox which uses a store to suggest values to a user as they type.

An example of which can be found here: combobox example

Is there a way of making it so the suggested text list is rendered to an element in the DOM. Please note I do not mean the "applyTo" config option, as this would render the whole control, including the textbox to the DOM element.

A: 

So clarify, you want the selected text to render somewhere besides directly below the text input. Correct?

ComboBox is just a composite of Ext.DataView, a text input, and an optional trigger button. There isn't an official option for what you want and hacking it to make it do what you want would be really painful. So, the easiest course of action (other than finding and using some other library with a component that does exactly what you want) is to build your own with the components above:

  1. Create a text box. You can use an Ext.form.TextField if you want, and observe the keyup event.
  2. Create a DataView bound to your store, rendering to whatever DOM element you want. Depending on what you want, listen to the 'selectionchange' event and take whatever action you need to in response to the selection. e.g., setValue on an Ext.form.Hidden (or plain HTML input type="hidden" element).
  3. In your keyup event listener, call the store's filter method (see doc), passing the field name and the value from the text field. e.g., store.filter('name',new RegEx(value+'.*'))

It's a little more work, but it's a lot shorter than writing your own component from scratch or hacking the ComboBox to behave like you want.

noah
+1  A: 

You can use plugin for this, since you can call or even override private methods from within the plugin:

var suggested_text_plugin = {

    init: function(o) {

        o.onTypeAhead = function() {
            // Original code from the sources goes here:

            if(this.store.getCount() > 0){
                var r = this.store.getAt(0);
                var newValue = r.data[this.displayField];
                var len = newValue.length;
                var selStart = this.getRawValue().length;
                if(selStart != len){
                    this.setRawValue(newValue);
                    this.selectText(selStart, newValue.length);
                }
            }

         // Your code to display newValue in DOM
         ......myDom.getEl().update(newValue);
        };
    }
};


// in combobox code:

var cb = new Ext.form.ComboBox({
    ....
    plugins: suggested_text_plugin,
    ....
});

I think it's even possible to create a whole chain of methods, calling original method before or after yours, but I haven't tried this yet.

Also, please don't push me hard for using non-standard plugin definition and invocation methodics (undocumented). It's just my way of seeing things.

EDIT:

I think the method chain could be implemented something like that (untested):

....
o.origTypeAhead = new Function(this.onTypeAhead.toSource());
// or just
o.origTypeAhead = this.onTypeAhead;
....

o.onTypeAhead = function() {
    // Call original
    this.origTypeAhead();
    // Display value into your DOM element
    ...myDom....
};
Thevs
A: 

@Thevs

I think you were on the right track.

What I did was override the initList method of Combobox.

    Ext.override(Ext.form.ComboBox, {
    initList : function(){

If you look at the code you can see the bit where it renders the list of suggestions to a dataview. So just set the apply to the dom element you want:

            this.view = new Ext.DataView({
            //applyTo: this.innerList,
            applyTo: "contentbox",
qui
A: 

@qui

Ok. I thought you want an extra DOM field (in addition to existing combo field).

But your solution would override a method in the ComboBox class, isn't it? That would lead to all your combo-boxes would render to the same DOM. Using a plugin would override only one particular instance.

Thevs
You're probably right, however in this case I will definitely only be using one combobox, so it doesn't really matter :)Thanks for the advice
qui
+1  A: 

@qui

Another thing to consider is that initList is not part of the API. That method could disappear or the behavior could change significantly in future releases of Ext. If you never plan on upgrading, then you don't need to worry.

noah