Cuadro combinado Extjs: ocultar el valor seleccionado de la lista desplegable

8

Estoy usando ExtJS 4 y estoy buscando una forma de ocultar el valor seleccionado actualmente de la lista desplegable del combo.

Entonces, en lugar de esto ("Alaska" actualmente seleccionado en el cuadro combinado):

comportamiento predeterminado del cuadro combinado

Quiero que la lista de valores se vea así:

ingrese la descripción de la imagen aquí

En mi caso, el cuadro combinado no es editable (es decir, no puede ingresar un valor arbitrario), no creo que tenga mucho sentido mostrar el valor seleccionado dos veces: una en el campo de entrada y otra en la lista desplegable. Ya veo lo que está seleccionado, quiero que la lista desplegable solo me muestre otras opciones que puedo seleccionar.

Hasta ahora no veo una manera fácil de hacerlo. Probablemente el mejor lugar para comenzar es filtrar la tienda de combobox, pero combobox usa sus propios filtros para la funcionalidad de búsqueda en vivo.

¿Alguien consideró este problema? ¿Estoy tratando de hacer algo extraño? Me sorprende que no haya podido encontrar ningún tema relacionado.

1
6

No creo que tengas muchas opciones aquí ... tal vez podrías hacer algo como esto:

Ext.define('Your.company.Combo', {
    extend: 'Ext.form.field.ComboBox',
    alias: 'widget.specialcombo',

    /**
    * @cfg {boolean} hideActive
    * True to hide any selected record. Defaults to <tt>true</tt>.
    */
    hideActive: true,

    /**
    * @private {Ext.data.Model[]} hideActive
    * A Array of selected records.
    */


    initComponent: function () {
        this.selectedRecords = [];

        this.callParent(arguments);

        this.on('select', this.onSelectionChange, this);
    },

    /**
    * @private onChangeSelection
    * eventhandler selections
    */
    onSelectionChange: function (me, recs) {
        if(!me.hideActive)
            return;
        // write the current selected back to the store (you need to suspend autoSync if active)
        me.store.add(me.selectedRecords);
        // set the selected as new recordlist
        me.selectedRecords = recs;
        // remove the selected from the store
        me.store.remove(recs);
    }
});

Ese ejemplo no ha sido probado en absoluto. Pero como la tienda está vinculada principalmente a BoundList, que no está conectada directamente al campo de texto, esto debería funcionar. Estás haciendo una especie de almacenamiento en caché aquí.

3
  • La idea me parece buena, pero el código no funciona. this.on('select', function () { this.onSelectionChange(); }, this);debe cambiarse para this.on('select',this.onSelectionChange, this);que funcione correctamente tampoco hideActive: falsetiene ningún efecto.
    pllee
    5 de septiembre de 2012 a las 3:53
  • gracias por ese consejo. He supervisado estas cosas. Arreglo está arriba
    sra
    5 de septiembre de 2012 a las 6:46
  • ¡Gracias, eso parece funcionar! Editó su código un poco y ahora es funcional. 6 de septiembre de 2012 a las 7:14
4

Se me ocurrió otra solución que parece aún más simple y una prueba rápida no revela efectos secundarios:

Podemos dejar la lógica de Combobox intacta, pero simplemente ocultar el elemento seleccionado a través de CSS:

.x-boundlist-selected {
    display: none;
}

¡Y listo, no vemos el artículo seleccionado! No sé qué tan confiable sería esto en el código de producción, pero aún así vale la pena considerarlo, creo ...


ACTUALIZAR. Aquí está la solución completa si desea controlar este comportamiento a través del indicador de configuración de Combobox:

Ext.define('My.ComboBox',  {
    extend: 'Ext.form.field.ComboBox',

    /**
     * @cfg {Boolean} hideActive=true
     * When true, hides the currently selected value from the dropdown list
     */
    hideActive: true,

    /**
     * Internal method that creates the BoundList
     */
    createPicker: function() {
      var picker = this.callParent(arguments);

      // honor the hideActive flag
      if(this.hideActive) {
        picker.addCls('x-boundlist-hideactive');
      }

      return picker;
    }
});

En algún lugar de tu CSS:

.x-boundlist-hideactive .x-boundlist-selected {
    display: none;
}

ACTUALIZACIÓN 2. ¡Encontré un problema de interfaz de usuario con mi enfoque!

Ocultar el elemento seleccionado de la lista desplegable introduce una peculiaridad en la navegación del teclado: aunque el elemento está oculto visualmente, todavía existe y Ext lo seleccionará cuando presione las teclas ARRIBA / ABAJO. Visualmente, eso significa que su selección desaparecerá en algún momento y tendrá que presionar ARRIBA / ABAJO una vez más para volver al siguiente elemento visible.

Hasta ahora no pude encontrar una solución fácil para esto. Mi mejor opción sería modificar itemSelectorla lista enlazada (que es una Vista de datos), configurándola en algo así .x-boundlist-item:not(.x-boundlist-selected)para que el elemento seleccionado no se incluya en la consulta.

Si bien el selector en sí funciona, no resuelve el problema porque la Vista realiza esta consulta de selector antes de que se apliquen clases adicionales (incluida la clase de elemento seleccionada) a los elementos (esto sucede en Ext.view.AbstractView.refresh () .

Además, esta solución provoca un error en la ubicación de la lista desplegable cuando aparece encima del cuadro combinado.

Tenía la sensación de que mi enfoque era demasiado fácil para trabajar sin problemas :)

3
  • Dejaré las respuestas inaceptadas por ahora, con curiosidad por ver si a alguien más se le ocurren otras ideas ... 6 de septiembre de 2012 a las 7:43
  • Esto depende totalmente de usted :) Pero de todos modos puede no aceptar las respuestas más adelante. Eso solo como información
    sra
    6 de septiembre de 2012 a las 7:45
  • Je, me olvidé de eso, gracias :) Por ahora acepto mi propia respuesta porque eso es lo que realmente hice en mi código. Me encantaría que Sencha hiciera algo al respecto en el futuro (por ejemplo, cuadros combinados tipo MacOS con alineación vertical flotante). 6 de septiembre de 2012 a las 16:04
2

Terminé usando una versión modificada de la solución de @ sra:

Ext.define('My.ComboBox',  {
    extend: 'Ext.form.field.ComboBox',

    /**
     * @cfg {Boolean} hideActive=true
     * When true, hides the currently selected value from the dropdown list
     */
    hideActive: true,

    /**
    * @private {Ext.data.Model[]} selectedRecords
    * A Array of selected records, used when hideActive is true
    */

    initComponent: function() {
        this.selectedRecords = [];

        this.callParent();
    },


    setValue: function(value, doSelect) {
        var store = this.store;

        if(this.hideActive) {
            store.suspendEvents(false);
            // write the current selected back to the store (you need to suspend autoSync if active)
            // do this BEFORE callParent so the currently selected record would be found in the store
            store.add(this.selectedRecords);
        }

        this.callParent(arguments);

        if(this.hideActive) {
            // set the selected as new recordlist
            this.selectedRecords = this.valueModels;
            // remove the selected from the store
            store.remove(this.valueModels);
            store.resumeEvents();
            store.fireEvent('refresh', store);
        }

        return this;
    }

});

La lógica de 'ocultación' es la misma, solo que la realizo en el setValuemétodo para asegurarme de que también funciona cuando se configura mediante programación el valor del combo, incluido el caso en el que el cuadro combinado se inicializa con un valor.

UPD Además, parece que store.add(this.selectedRecords);se debe llamar antes this.callParent(arguments); , de lo contrario, el combobox actuará de manera extraña si intentamos establecer el mismo valor dos veces (simplemente no encontraría el registro activo en la tienda porque lo eliminamos, por lo que se restablecerá en blanco ). Suspendo los eventos de la tienda para evitar algunas peculiaridades causadas por el combobox que intenta sincronizar con su lista desplegable en medio de mis manipulaciones con los registros seleccionados y disparo manualmente el 'refresh'evento de la tienda cuando termino para que la lista se actualice eventualmente. Esto puede tener un impacto en el rendimiento, pero hasta ahora no conozco una solución mejor.

2

ExtJS 3 Escribí esta respuesta basada en las demás. Funciona muy bien para mí, aunque está un poco modificado de lo que estás buscando.

Name.space.name = new Ext.extend(Ext.form.ComboBox, {
    type: 'all',
    oldrec: null,
    store: null,
    constructor: function (config) {
        var me = this;
        if (config.type === 'all') {
            me.store = AllConditionStore;
        } else {
            me.store = ?.?('RuleParameterType');
        }
        config = Ext.apply({
            store: me.store,
            valueField: 'id',
            hideActive: true,
            triggerAction: 'all',
            lazyRender: true,
            allowBlank: false,
            mode: 'local',
            displayField: 'text',
            listeners: {
                select: function (me, recs, index) {
                    if (me.oldrec !== null)
                        me.store.add(me.oldrec);
                    me.oldrec = recs;
                    // remove the selected from the store
                    me.store.remove(recs);
                    // redo store
                }
            }
        }, config);
        ?.?.Parameter.superclass.constructor.call(this, config);
    }
});
0

Entonces usé la solución de @ sra, pero con una pequeña modificación, para agregar el contenido en el lugar correcto debajo de if(!me.hideActive):

if(me.selectedRecords[0]) {
    me.store.insert(me.selectedRecords[0].index,me.selectedRecords);
}

De esa manera, simplemente no los agregas al botón. Sé que es una publicación antigua, pero espero que ayude a las personas que buscan una solución.