- * - 'remote' : Default
- *
Automatically loads the {@link #store} the first time the trigger
- * is clicked. If you do not want the store to be automatically loaded the first time the trigger is
- * clicked, set to 'local' and manually load the store. To force a requery of the store
- * every time the trigger is clicked see {@link #lastQuery}.
- * - 'local' :
+ *
'remote'
: Default
+ * In queryMode: 'remote'
, the ComboBox loads its Store dynamically based upon user interaction.
+ * This is typically used for "autocomplete" type inputs, and after the user finishes typing, the Store is {@link Ext.data.Store#load load}ed.
+ * A parameter containing the typed string is sent in the load request. The default parameter name for the input string is query
, but this
+ * can be configured using the {@link #queryParam} config.
+ * In queryMode: 'remote'
, the Store may be configured with {@link Ext.data.Store#remoteFilter remoteFilter}: true
,
+ * and further filters may be programatically added to the Store which are then passed with every load request which allows the server
+ * to further refine the returned dataset.
+ * Typically, in an autocomplete situation, {@link #hideTrigger} is configured true
because it has no meaning for autocomplete.
+ * 'local'
:
* ComboBox loads local data
*
var combo = new Ext.form.field.ComboBox({
@@ -190,54 +205,56 @@ var combo = new Ext.form.field.ComboBox({
queryCaching: true,
/**
- * @cfg {Number} pageSize If greater than 0, a {@link Ext.toolbar.Paging} is displayed in the
+ * @cfg {Number} pageSize If greater than 0
, a {@link Ext.toolbar.Paging} is displayed in the
* footer of the dropdown list and the {@link #doQuery filter queries} will execute with page start and
- * {@link Ext.toolbar.Paging#pageSize limit} parameters. Only applies when {@link #queryMode} = 'remote'
- * (defaults to 0).
+ * {@link Ext.toolbar.Paging#pageSize limit} parameters. Only applies when {@link #queryMode} = 'remote'
+ * (defaults to 0
).
*/
pageSize: 0,
/**
* @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and
- * sending the query to filter the dropdown list (defaults to 500 if {@link #queryMode} = 'remote'
- * or 10 if {@link #queryMode} = 'local')
+ * sending the query to filter the dropdown list (defaults to 500
if {@link #queryMode} = 'remote'
+ * or 10
if {@link #queryMode} = 'local'
)
*/
/**
* @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and
- * {@link #typeAhead} activate (defaults to 4 if {@link #queryMode} = 'remote' or 0 if
- * {@link #queryMode} = 'local', does not apply if {@link Ext.form.field.Trigger#editable editable} = false).
+ * {@link #typeAhead} activate (defaults to 4
if {@link #queryMode} = 'remote'
or 0
if
+ * {@link #queryMode} = 'local'
, does not apply if {@link Ext.form.field.Trigger#editable editable} = false
).
*/
/**
- * @cfg {Boolean} autoSelect true to select the first result gathered by the data store (defaults
- * to true). A false value would require a manual selection from the dropdown list to set the components value
- * unless the value of ({@link #typeAhead}) were true.
+ * @cfg {Boolean} autoSelect true
to automatically highlight the first result gathered by the data store
+ * in the dropdown list when it is opened. (Defaults to true
). A false value would cause nothing in the
+ * list to be highlighted automatically, so the user would have to manually highlight an item before pressing
+ * the enter or {@link #selectOnTab tab} key to select it (unless the value of ({@link #typeAhead}) were true),
+ * or use the mouse to select a value.
*/
autoSelect: true,
/**
- * @cfg {Boolean} typeAhead true to populate and autoselect the remainder of the text being
+ * @cfg {Boolean} typeAhead true
to populate and autoselect the remainder of the text being
* typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults
- * to false)
+ * to false
)
*/
typeAhead: false,
/**
* @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
- * if {@link #typeAhead} = true (defaults to 250)
+ * if {@link #typeAhead} = true
(defaults to 250
)
*/
typeAheadDelay: 250,
/**
* @cfg {Boolean} selectOnTab
- * Whether the Tab key should select the currently highlighted item. Defaults to true.
+ * Whether the Tab key should select the currently highlighted item. Defaults to true
.
*/
selectOnTab: true,
/**
- * @cfg {Boolean} forceSelection true to restrict the selected value to one of the values in the list,
- * false to allow the user to set arbitrary text into the field (defaults to false)
+ * @cfg {Boolean} forceSelection true
to restrict the selected value to one of the values in the list,
+ * false
to allow the user to set arbitrary text into the field (defaults to false
)
*/
forceSelection: false,
@@ -264,7 +281,7 @@ var combo = new Ext.form.field.ComboBox({
});
*
* To make sure the filter in the store is not cleared the first time the ComboBox trigger is used
- * configure the combo with lastQuery=''. Example use:
+ * configure the combo with lastQuery=''
. Example use:
*
var combo = new Ext.form.field.ComboBox({
...
@@ -292,7 +309,7 @@ var combo = new Ext.form.field.ComboBox({
/**
* @cfg {Mixed} transform
- * The id, DOM node or {@link Ext.core.Element} of an existing HTML <select> element to
+ * The id, DOM node or {@link Ext.core.Element} of an existing HTML <select>
element to
* convert into a ComboBox. The target select's options will be used to build the options in the ComboBox
* dropdown; a configured {@link #store} will take precedence over this.
*/
@@ -307,13 +324,13 @@ var combo = new Ext.form.field.ComboBox({
* - {@link Ext.view.BoundList#emptyText} - defaults to empty string
* - {@link Ext.view.BoundList#getInnerTpl} - defaults to the template defined in BoundList
* - {@link Ext.view.BoundList#itemSelector} - defaults to the value defined in BoundList
- * - {@link Ext.view.BoundList#loadingText} - defaults to 'Loading...'
- * - {@link Ext.view.BoundList#minWidth} - defaults to 70
- * - {@link Ext.view.BoundList#maxWidth} - defaults to undefined
- * - {@link Ext.view.BoundList#maxHeight} - defaults to 300
- * - {@link Ext.view.BoundList#resizable} - defaults to false
- * - {@link Ext.view.BoundList#shadow} - defaults to 'sides'
- * - {@link Ext.view.BoundList#width} - defaults to undefined (automatically set to the width
+ *
- {@link Ext.view.BoundList#loadingText} - defaults to
'Loading...'
+ * - {@link Ext.view.BoundList#minWidth} - defaults to
70
+ * - {@link Ext.view.BoundList#maxWidth} - defaults to
undefined
+ * - {@link Ext.view.BoundList#maxHeight} - defaults to
300
+ * - {@link Ext.view.BoundList#resizable} - defaults to
false
+ * - {@link Ext.view.BoundList#shadow} - defaults to
'sides'
+ * - {@link Ext.view.BoundList#width} - defaults to
undefined
(automatically set to the width
* of the ComboBox field if {@link #matchFieldWidth} is true)
*
*/
@@ -560,9 +577,9 @@ var combo = new Ext.form.field.ComboBox({
* Executes a query to filter the dropdown list. Fires the {@link #beforequery} event prior to performing the
* query allowing the query action to be canceled if needed.
* @param {String} queryString The SQL query to execute
- * @param {Boolean} forceAll
true to force the query to execute even if there are currently fewer
- * characters in the field than the minimum specified by the
{@link #minChars} config option. It
- * also clears any filter previously saved in the current store (defaults to
false)
+ * @param {Boolean} forceAll
true
to force the query to execute even if there are currently fewer
+ * characters in the field than the minimum specified by the
{@link #minChars}
config option. It
+ * also clears any filter previously saved in the current store (defaults to
false
)
* @return {Boolean} true if the query was permitted to run, false if it was cancelled by a {@link #beforequery} handler.
*/
doQuery: function(queryString, forceAll) {
@@ -596,12 +613,19 @@ var combo = new Ext.form.field.ComboBox({
// make sure they aren't querying the same thing
if (!me.queryCaching || me.lastQuery !== queryString) {
me.lastQuery = queryString;
- store.clearFilter(!forceAll);
+
if (isLocalMode) {
- if (!forceAll) {
+ // forceAll means no filtering - show whole dataset.
+ if (forceAll) {
+ store.clearFilter();
+ } else {
+ // Clear filter, but supress event so that the BoundList is not immediately updated.
+ store.clearFilter(true);
store.filter(me.displayField, queryString);
}
} else {
+ // In queryMode: 'remote', we assume Store filters are added by the developer as remote filters,
+ // and these are automatically passed as params with every load call, so we do *not* call clearFilter.
store.load({
params: me.getParams(queryString)
});
@@ -628,8 +652,13 @@ var combo = new Ext.form.field.ComboBox({
// private
getParams: function(queryString) {
var p = {},
- pageSize = this.pageSize;
- p[this.queryParam] = queryString;
+ pageSize = this.pageSize,
+ param = this.queryParam;
+
+ if (param) {
+ p[param] = queryString;
+ }
+
if (pageSize) {
p.start = 0;
p.limit = pageSize;
@@ -698,14 +727,23 @@ var combo = new Ext.form.field.ComboBox({
me.doQueryTask.delay(me.queryDelay);
}
}
+
+ if (me.enableKeyEvents) {
+ me.callParent(arguments);
+ }
},
initEvents: function() {
var me = this;
me.callParent();
- // setup keyboard handling
- me.mon(me.inputEl, 'keyup', me.onKeyUp, me);
+ /*
+ * Setup keyboard handling. If enableKeyEvents is true, we already have
+ * a listener on the inputEl for keyup, so don't create a second.
+ */
+ if (!me.enableKeyEvents) {
+ me.mon(me.inputEl, 'keyup', me.onKeyUp, me);
+ }
},
createPicker: function() {
@@ -723,7 +761,8 @@ var combo = new Ext.form.field.ComboBox({
store: me.store,
displayField: me.displayField,
focusOnToFront: false,
- pageSize: me.pageSize
+ pageSize: me.pageSize,
+ tpl: me.tpl
}, me.listConfig, me.defaultListConfig);
picker = me.picker = Ext.create('Ext.view.BoundList', opts);
@@ -734,10 +773,7 @@ var combo = new Ext.form.field.ComboBox({
scope: me
});
- me.mon(picker.getSelectionModel(), {
- selectionChange: me.onListSelectionChange,
- scope: me
- });
+ me.mon(picker.getSelectionModel(), 'selectionchange', me.onListSelectionChange, me);
return picker;
},
@@ -746,7 +782,7 @@ var combo = new Ext.form.field.ComboBox({
this.alignPicker();
this.syncSelection();
},
-
+
onItemClick: function(picker, record){
/*
* If we're doing single selection, the selection change events won't fire when
@@ -756,25 +792,34 @@ var combo = new Ext.form.field.ComboBox({
lastSelection = me.lastSelection,
valueField = me.valueField,
selected;
-
+
if (!me.multiSelect && lastSelection) {
selected = lastSelection[0];
- if (record.get(valueField) === selected.get(valueField)) {
+ if (selected && (record.get(valueField) === selected.get(valueField))) {
me.collapse();
}
- }
+ }
},
onListSelectionChange: function(list, selectedRecords) {
- var me = this;
+ var me = this,
+ isMulti = me.multiSelect,
+ hasRecords = selectedRecords.length > 0;
// Only react to selection if it is not called from setValue, and if our list is
// expanded (ignores changes to the selection model triggered elsewhere)
if (!me.ignoreSelection && me.isExpanded) {
- if (!me.multiSelect) {
+ if (!isMulti) {
Ext.defer(me.collapse, 1, me);
}
- me.setValue(selectedRecords, false);
- if (selectedRecords.length > 0) {
+ /*
+ * Only set the value here if we're in multi selection mode or we have
+ * a selection. Otherwise setValue will be called with an empty value
+ * which will cause the change event to fire twice.
+ */
+ if (isMulti || hasRecords) {
+ me.setValue(selectedRecords, false);
+ }
+ if (hasRecords) {
me.fireEvent('select', me, selectedRecords);
}
me.inputEl.focus();
@@ -1019,3 +1064,4 @@ var combo = new Ext.form.field.ComboBox({
}
}
});
+