2012-09-04 88 views
7

Estoy usando ExtJS 4 y estoy buscando una forma en que pueda ocultar el valor seleccionado actualmente de la lista desplegable del combo.Extjs combobox: ocultar el valor seleccionado de la lista desplegable

Así que en lugar de esto ("Alaska" actualmente seleccionado en cuadro combinado):

default combobox behaviour

Quiero la lista de valores este aspecto:

enter image description here

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

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

¿Alguien ha considerado este problema? ¿Estoy tratando de hacer algo raro? Me sorprende que no haya podido encontrar ningún tema relacionado.

+0

Preguntada la misma pregunta en el foro de Sencha: http://www.sencha.com/forum/showthread.php?241063-Combobox-hide-selected-value-from-dropdown-list&p=882210 –

Respuesta

1

terminé usando una versión modificada de @ sra es tan lución:

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; 
    } 

}); 

El 'esconde' la lógica es la misma, sólo se llevo a cabo en el método setValue para asegurarse de que también funciona cuando mediante programación el valor de ajuste de combo, incluyendo el caso en el que el cuadro combinado se inicializa con un valor .

UPD Además, parece que store.add(this.selectedRecords); tiene que ser llamado antes this.callParent(arguments);, de lo contrario cuadro combinado actuará raro si se intenta 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). Suspendí los eventos de la tienda para evitar algunas peculiaridades causadas por el cuadro combinado que intenta sincronizar con su lista desplegable en medio de mis manipulaciones con registros seleccionados y desencadenar manualmente el evento 'refresh' del almacén cuando termino para que la lista se actualice finalmente. Esto puede tener un impacto en el rendimiento, pero hasta ahora no conozco una mejor solución.

5

Yo no creo que hay que hay muchas opciones aquí ... tal vez podría 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 es totalmente no probado. Pero como la tienda está principalmente vinculada a la BoundList que no está directamente conectada al campo de texto, esto debería funcionar. Usted está haciendo una especie de almacenamiento en caché aquí.

+0

La idea parece buena para pero el código no funcionará 'this.on ('select', function() {this.onSelectionChange();}, this);' debe cambiarse a 'this.on ('select', this.onSelectionChange, this);' para que funcione correctamente también 'hideActive: false' no tiene ningún efecto. – pllee

+0

gracias por ese consejo. He supervisado estas cosas. Se corrigió la reparación – sra

+0

¡Gracias, eso parece hacer el truco! Editó su código un poco y ahora es funcional. –

3

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

podemos dejar lógica Combobox intacto sino simplemente ocultar el elemento seleccionado a través de CSS:

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

Y voila, ¡no vemos el elemento seleccionado! No sé qué tan confiable esto sería en el código de producción, pero todavía vale la pena considerar, creo ...


UPDATE. Aquí está la solución completa si desea controlar este comportamiento a través de la bandera de configuración del cuadro combinado:

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. encontrado un problema con la interfaz de usuario ¡mi acercamiento!

Ocultar el elemento seleccionado de la lista desplegable introduce una peculiaridad en la navegación por el 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 a colocarla en el siguiente elemento visible.

Hasta ahora no he podido encontrar una solución fácil para esto. Mi mejor opción sería modificar itemSelector de la lista encuadernada (que es una Vista de datos), configurándola en algo como .x-boundlist-item:not(.x-boundlist-selected) para que el elemento seleccionado no entre en la consulta.

Mientras el selector en sí funciona, no resuelve el problema, porque la vista realiza esta consulta de selección antes de las clases adicionales (incluyendo la clase de elemento seleccionado) obtener aplicado a los elementos (esto ocurre en Ext.view.AbstractView.refresh().

además, esta solución provoca una mala colocació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 :)

+0

Buen punto y mucho más rápido, supongo. Nunca lo intenté. – sra

+0

Dejaré las respuestas sin respuesta por el momento, con curiosidad de ver si alguien más tiene otras ideas ... –

+0

Esto depende de ti :) Pero puedes dejar de recibir respuestas más tarde de todos modos.Eso solo como información – sra

1

ExtJS 3 Escribí esta respuesta basándome en las demás. Funciona muy bien para mí, es 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

por lo que utiliza @ solución de SRA, pero con una pequeña modificación, para agregar el contenido en el lugar correcto por debajo de la if(!me.hideActive):

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

De esa manera simplemente no añadirlos a la botton Sé que es una publicación anterior, pero espero que ayude a las personas que buscan una solución.

Cuestiones relacionadas