#javascript #extjs #combobox #extjs3
#javascript #extjs #поле со списком #extjs3
Вопрос:
Я открыл проект ExtJS, над которым я некоторое время не задумывался, и это ставит меня в тупик.
У меня есть Ext.form.Поле со списком, использующее удаленное хранилище JSON для составления списка пользователей. Я использую XTemplate для форматирования пользователей, перечисленных в раскрывающемся списке:
'<tpl for="."><div class="x-combo-list-item">',
'{firstname} {lastname} ({email})',
'</div></tpl>'
Когда я раскрываю выпадающий список, я вижу, что мои пользователи перечислены правильно:
Джон Смит (jsmith@company.com )
Джон Форд (jford@company.com )
Однако, когда я нажимаю на пользователя, содержимое поля со списком изменяется на свойство valueField (‘firstname’), которое вы ожидаете.
Проблемы:
-
Вместо того, чтобы показывать Джона, я бы хотел, чтобы в поле со списком отображалось: Джон Смит (jsmith@company.com ).
-
Когда у меня есть два имени Джона (Джон Смит и Джон Форд) и загружается форма, логика ExtJS сопоставляется с первым именем Джона, которое она находит в списке, и изменяет значение поля на первое имя Джона, с которым оно сопоставляется.
Например: Джон Смит (ID = 1) Джон Форд (ID = 2)
Пользователь выбирает Джона Форда, и «Джон» появляется в поле со списком после того, как он щелкнул по пункту меню со списком, и user_id = 2 записывается в базу данных.
Однако, когда я перезагружаю страницу, имя «John» сопоставляется (загружается из базы данных) с первой записью списка, и если оператор вручную не изменяет выбор в выпадающем диалоговом окне, то выбирается John Smith и user_id = 1 теперь записывается в базу данных (когда пользователь сохраняет форму).
Любой ввод был бы высоко оценен. Моя интуиция подсказывает мне, что во время загрузки и отправки списка должно быть несколько перехватов, которые позволят мне манипулировать тем, что записано в элемент innerHTML элемента.
~~~~~~~~~~~~~
Примечание: Я унаследовал от пользовательского класса, который позволяет мне вводить предварительный запрос по имени, фамилии и адресу электронной почты (поскольку у нас потенциально могут быть сотни пользователей для поиска).
Элемент ComboBox, который я наследую от:
CW.form.CustomComboBox = Ext.extend( Ext.form.ComboBox, {
filterKeys:[],
// Note: This overrides the standard doQuery function in Ext 3.3
doQuery: function(q, forceAll){
q = Ext.isEmpty(q) ? '' : q;
var qe = {
query: q,
forceAll: forceAll,
combo: this,
cancel:false
};
if(this.fireEvent('beforequery', qe)===false || qe.cancel){
return false;
}
q = qe.query;
forceAll = qe.forceAll;
if(forceAll === true || (q.length >= this.minChars)){
if(this.lastQuery !== q){
this.lastQuery = q;
if(this.mode == 'local'){
this.selectedIndex = -1;
if(forceAll){
this.store.clearFilter();
}else{
// this.store.filter(this.displayField, q);
this.store.filterBy( function(rec,id){
return this.filterFn(rec,id,q);
}, this );
}
this.onLoad();
}else{
this.store.baseParams[this.queryParam] = q;
this.store.load({
params: this.getParams(q)
});
this.expand();
}
}else{
this.selectedIndex = -1;
this.onLoad();
}
}
},
/**
* Custom function for filtering the store
*/
filterFn: function(rec, id, q ){
// var filterKeys = ['id', 'firstname', 'lastname', 'email'];
var parts = q.split(' ');
// If no filter applied then show no results
if(parts.length == 0){
return false;
}
// Iterate through each of the parts of the user string
// They must all match, at least in part, one of the filterKeys
// (i.e. id, email, firstname, etc.)
for(i=0; i<parts.length;i ){
var foundPart = false;
// Create a RegExp object for this search snippet (i.e. '@gmai')
var matcher = this.store.data.createValueMatcher(parts[i] , true);
// Search until this matches one of the keys for this record
for(j=0;j<this.filterKeys.length; j ){
if(matcher.test(rec.get(this.filterKeys[j]))){
foundPart = true;
break;
}
}
// If there are no fields of the record matching this part,
// the record does not match (return false)
if( foundPart == false ){
return false;
}
}
return true;
},
initComponent: function(){
Ext.applyIf(this,{
listeners:{
beforequery: function(qe){
delete qe.combo.lastQuery;
return true;
}
}
});
if(this.filterKeys.length == 0){
this.filterKeys = [this.displayField];
}
CW.form.CustomComboBox.superclass.initComponent.call(this);
}
});
Ext.reg('custom-combo', CW.form.CustomComboBox);
Ответ №1:
Что касается проблемы № 1, лучший способ, который я нашел для получения хороших пользовательских полей отображения, — это использовать сгенерированные поля во внешних данных.Определение записи, используемое хранилищем. Таким образом, вы получаете доступ к полной записи для создания вашего поля отображения и не ограничиваетесь только одним полем. Я не могу найти примеры 3.x в Интернете сейчас, когда Sencha переходит на Ext4, но вы можете найти этот пример в examples/form
каталоге вашей загрузки ExtJS. Здесь я изменил один из примеров со списком ExtJS ( examples/form/combo.js
):
var store = new Ext.data.ArrayStore({
fields: ['abbr', 'state', 'nick', {
name: 'display',
convert: function(v, rec) { return rec[1] ' - ' rec[0] }
// display looks like 'Texas - TX'
}],
data : Ext.exampledata.states // from states.js
});
var combo = new Ext.form.ComboBox({
store: store,
displayField:'display',
typeAhead: true,
mode: 'local',
forceSelection: true,
triggerAction: 'all',
emptyText:'Select a state...',
selectOnFocus:true,
applyTo: 'local-states'
});
И теперь в поле со списком отображаются такие значения, как Texas - TX
или что бы вы ни convert
выводили. Документацию для этого можно найти convert
в Ext.data.Документы по полю.
Что касается проблемы № 2, возможно, вам потребуется установить idProperty
для ваших внешних данных.Reader или ваше хранилище, если вы используете одну из удобных комбинаций store reader, такую как JSONStore или ArrayStore. idProperty
указывает Ext, в каком поле искать уникальный идентификатор. Вы можете столкнуться со всевозможными странностями, если у вас их нет idProperty
или вы выбираете одно, которое не является уникальным. Документы для этого находятся здесь.
Комментарии:
1. Чудесно, сработало как по волшебству. Что касается пункта # 2 — у меня действительно был установлен idProprety, но беглые тесты показывают, что это исправлено в результате вашего решения для # 1. Приветствия!
2. Спасибо за это решение, оно было очень полезно для моего проекта 🙂
Ответ №2:
Вам просто нужно заменить ваше displayField приведенным ниже кодом
tpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<div class="x-boundlist-item">{firstName} {lastName} {email}</div>',
'</tpl>'
),
// template for the content inside text field
displayTpl: Ext.create('Ext.XTemplate',
'<tpl for=".">',
'firstName} {lastName} {email}',
'</tpl>'
)
Комментарии:
1. Для меня это частично работает, когда я нажимаю на выпадающий список, в раскрывающемся списке отображаются значения displayField, а не значения xtemplete.