/**
* Simple Select field wrapper. Example usage:
<pre><code>
new Ext.field.Select({
options: [
{text: 'First Option', value: 'first'},
{text: 'Second Option', value: 'second'},
{text: 'Third Option', value: 'third'}
]
});
</code></pre>
*/
Ext.define('Ext.field.Select', {
extend: 'Ext.field.Text',
alias : 'widget.selectfield',
alternateClassName: 'Ext.form.Select',
requires: [
'Ext.Panel',
'Ext.picker.Picker',
'Ext.data.Store',
'Ext.data.StoreManager'
],
/**
* @event change
* Fires when an option selection has changed
* @param {Ext.field.Select} this
* @param {Mixed} value
*/
config: {
// @inherit
ui: 'select',
/**
* @cfg {Number} tabIndex
* @hide
*/
tabIndex: -1,
/**
* @cfg {Boolean} useClearIcon
* @hide
*/
/**
* @cfg {String/Number} valueField The underlying {@link Ext.data.Field#name data value name} (or numeric Array index) to bind to this
* Select control. (defaults to 'value')
* @accessor
*/
valueField: 'value',
/**
* @cfg {String/Number} displayField The underlying {@link Ext.data.Field#name data value name} (or numeric Array index) to bind to this
* Select control. This resolved value is the visibly rendered value of the available selection options.
* (defaults to 'text')
* @accessor
*/
displayField: 'text',
/**
* @cfg {Ext.data.Store} store (Optional) store instance used to provide selection options data.
* @accessor
*/
store: null,
/**
* @cfg {Array} options (Optional) An array of select options.
<pre><code>
[
{text: 'First Option', value: 'first'},
{text: 'Second Option', value: 'second'},
{text: 'Third Option', value: 'third'}
]
</code></pre>
* Note: option object member names should correspond with defined {@link #valueField valueField} and {@link #displayField displayField} values.
* This config will be ignore if a {@link #store store} instance is provided
* @accessor
*/
options: null,
/**
* @cfg {String} hiddenName Specify a hiddenName if you're using the {@link Ext.form.Panel#standardSubmit standardSubmit} option.
* This name will be used to post the underlying value of the select to the server.
* @accessor
*/
hiddenName: null,
/**
* @cfg {Object} input
* @hide
*/
component: {
useMask: true
},
/**
* @cfg {Boolean} clearIcon
* @hide
* @accessor
*/
clearIcon: false
},
/**
* @private
*/
record: null,
/**
* @private
*/
previousRecord: null,
// @private
constructor: function(config) {
config = config || {};
if (!config.store) {
config.store = true;
}
this.callParent([config]);
},
// @private
initialize: function() {
this.getComponent().on({
scope: this,
masktap: 'onMaskTap'
});
this.callParent();
},
applyValue: function(value) {
var record = value,
index;
if (!(value instanceof Ext.data.Model)) {
index = this.getStore().find(this.getValueField(), value);
if (index == -1) {
index = this.getStore().find(this.getDisplayField(), value);
}
record = this.getStore().getAt(index);
}
return record;
},
updateValue: function(newValue, oldValue) {
this.previousRecord = oldValue;
if (newValue) {
this.record = newValue;
this.callParent([newValue.get(this.getDisplayField())]);
}
this.fireAction('change', [this, newValue, oldValue]);
},
getValue: function() {
var record = this.record;
return (record) ? record.get(this.getValueField()) : null;
},
getRecord: function() {
return this.record;
},
// @private
getPicker: function() {
if (!this.picker) {
this.picker = Ext.create('Ext.picker.Picker', {
slots: [{
align : 'center',
name : this.getName(),
valueField : this.getValueField(),
displayField: this.getDisplayField(),
value : this.getValue(),
store : this.getStore()
}],
listeners: {
change: this.onPickerChange,
scope: this
}
});
}
return this.picker;
},
// @private
getListPanel: function() {
if (!this.listPanel) {
this.listPanel = Ext.create('Ext.Panel', {
top : 0,
left : 0,
height : 200,
modal : true,
cls : Ext.baseCSSPrefix + 'select-overlay',
layout : 'fit',
hideOnMaskTap: true,
items: {
xtype: 'list',
store: this.getStore(),
itemTpl: '<span class="x-list-label">{' + this.getDisplayField() + '}</span>',
listeners: {
select : this.onListSelect,
itemtap: this.onListTap,
scope : this
}
}
});
}
return this.listPanel;
},
// @private
onMaskTap: function() {
if (this.getDisabled()) {
return false;
}
this.showComponent();
return false;
},
// @private
showComponent: function() {
if (Ext.os.deviceType == 'Phone') {
var picker = this.getPicker(),
name = this.getName(),
value = {};
value[name] = this.record.get(this.getValueField());
picker.setValue(value);
picker.show();
} else {
var listPanel = this.getListPanel(),
list = listPanel.down('list'),
store = list.getStore(),
index = store.find(this.getValueField(), this.getValue()),
record = store.getAt((index == -1) ? 0 : index);
listPanel.showBy(this);
list.select(record, null, true);
}
},
// @private
onListSelect: function(item, record) {
var me = this;
if (record) {
me.setValue(record);
}
},
onListTap: function() {
this.listPanel.hide({
type : 'fade',
out : true,
scope: this
});
},
// @private
onPickerChange: function(picker, value) {
var me = this,
currentValue = me.getValue(),
newValue = value[me.getName()],
store = me.getStore(),
index = store.find(me.getValueField(), newValue);
record = store.getAt(index);
me.setValue(record);
},
/**
* Updates the underlying <options> list with new values.
* @param {Array} options An array of options configurations to insert or append.
<pre><code>
selectBox.setOptions(
[ {text: 'First Option', value: 'first'},
{text: 'Second Option', value: 'second'},
{text: 'Third Option', value: 'third'}
]).setValue('third');
</code></pre>
* Note: option object member names should correspond with defined {@link #valueField valueField} and
* {@link #displayField displayField} values.
* @return {Ext.field.Select} this
*/
updateOptions: function(newOptions) {
var store = this.getStore(),
record;
if (!newOptions) {
store.clearData();
this.setValue(null);
}
else {
store.loadData(newOptions);
record = store.getAt(0);
this.setValue(record);
}
},
applyStore: function(store) {
if (store === true) {
store = Ext.create('Ext.data.Store', {
fields: [this.getValueField(), this.getDisplayField()]
});
}
if (store) {
store = Ext.data.StoreManager.lookup(store);
}
return store;
},
updateStore: function(newStore) {
var record = (newStore) ? newStore.getAt(0) : null;
if (newStore && record) {
this.setValue(record);
}
},
/**
* Resets the Select field to the value of the first record in the store.
* @return {Ext.field.Select} this
*/
reset: function() {
var store = this.getStore(),
record = (this.originalValue) ? this.originalValue : store.getAt(0);
if (store && record) {
this.setValue(record);
}
return this;
},
destroy: function() {
this.callParent(arguments);
Ext.destroy(this.listPanel, this.picker, this.hiddenField);
}
});