Итак, я разместил эту статью на прошлой неделе на форумах ExtJS, но никто не ответил, и я немного схожу с ума, пытаясь понять:
Я довольно плохо знаком с ExtJS (только что изучил его на прошлой неделе для работы), но я уже довольно давно работаю с другими библиотеками JavaScript. Я делаю пользовательский элемент управления для редактирования списка атрибутов (в настоящее время заполняется запросом JSON). Я использую PropertyGrid с пользовательским GridEditor (созданным путем расширения различных полей Ext.form). Все мои настраиваемые поля работают, кроме одного, который является редактором повторяющихся значений. По сути, поле будет передаваться в виде простого 2d массива пары ключ / значение по запросу JSON, который отображается в EditorGridPanel (внутри созданного мной Ext.Window).
Вот раздел запроса JSON, который определяет редактор повторяющихся значений:
{
key: 'Repeating',
type: 'repeating',
category: 'Category A',
options: {
dataArray: [
{key: 'key A', value: 'value A'},
{key: 'key B', value: 'value B'},
{key: 'key C', value: 'value C'}
]
}
}
Клавиша - это имя поля (отображается в левом столбце PropertyGrid).
Тип сообщает функции, которая создает все редакторы сетки, какой тип пользовательского редактора использовать.
Категория используется для определения того, к какой PropertyGrid добавлен GridEditor (у меня есть несколько PropertyGird, все они содержатся в Panel с макетом: «acordion»).
Все в options добавляется в расширенное поле Ext.form при его создании.
Итак, dataArray присоединен к моему повторяющемуся редактору значений для настройки начальных пар ключ / значение и для сохранения массива, переданного обратно в GridEditor посредством Ext.Window, используемого для его редактирования.
После некоторых экспериментов я решил использовать TriggerField в качестве GridEditor для моего повторяющегося типа значения. Вот код для определения повторяющегося поля значения:
Ext.form.customFields = {
'repeating': Ext.extend(Ext.form.TriggerField, {
triggerClass: 'x-form-edit-trigger',
enableKeyEvents: true
})
};
А вот код, который его устанавливает:
Ext.form.customFields['repeating'] = Ext.extend(Ext.form.customFields['repeating'], {
onTriggerClick: function()
{
this.editorWindow.show();
},
listeners: {
'render': function(field)
{
field.editorWindow = new Ext.MultiSelectWindow({
data: field.dataArray,
parent: field
});
},
'keydown': function(field, event)
{
event.stopEvent();
},
'beforerender': function()
{
for (i in this.opt) {
if (i != 'store') {
this[i] = this.opt[i];
}
else {
this.store.loadData(this.opt.store);
}
}
if (this.regex != undefined) {
this.validator = function(value)
{
return this.regex.test(value);
};
}
}
}
});
И, наконец, вот код для окна пользовательского редактора:
Ext.MultiSelectWindow = function(args)
{
var obj = this;
obj.args = args;
obj.KeyValue = new Ext.data.Record.create([{
name: 'key'
}, {
name: 'value'
}]);
obj.gridStore = new Ext.data.Store({
data: obj.args.data,
reader: new Ext.data.JsonReader({}, obj.KeyValue),
autoLoad: true
});
obj.cm = new Ext.grid.ColumnModel([{
id: 'key',
header: "Key",
dataIndex: 'key',
editor: new Ext.form.TextField({
allowBlank: false
}),
hideable: false,
sortable: false,
menuDisabled: true,
css: 'font-weight: bold;'
}, {
id: 'value',
header: "Value",
dataIndex: 'value',
editor: new Ext.form.TextField({}),
hideable: false,
sortable: false,
menuDisabled: true
}]);
obj.gridEditor = new Ext.grid.EditorGridPanel({
cm: obj.cm,
height: 280,
store: obj.gridStore,
autoExpandColumn: 'value',
listeners: {
'render': function()
{
// set up local aliases
obj.a = new Array();
obj.a.grid = obj.gridEditor;
obj.a.store = obj.a.grid.getStore();
obj.a.sel = obj.a.grid.getSelectionModel();
}
},
bbar: [{
text: 'Add',
cls: 'x-btn-text-icon',
icon: '/lib/images/add.png',
listeners: {
'click': function()
{
var kv = new obj.KeyValue({
key: '',
value: ''
});
var row = obj.a.store.data.items.length;
obj.a.grid.stopEditing();
obj.a.store.insert(row, kv);
obj.a.grid.startEditing(row, 0);
}
}
}, {
text: 'Delete',
cls: 'x-btn-text-icon',
icon: '/lib/images/delete.png',
listeners: {
'click': function()
{
if (obj.a.sel.selection)
obj.a.store.remove(obj.a.sel.selection.record);
}
}
}]
});
obj.panelAll = new Ext.Panel({
border: false,
layout: 'absolute',
items: [new Ext.Panel({
width: 250,
border: false,
x: 0,
y: 0,
items: obj.gridEditor
}), new Ext.Panel({
border: false,
x: 254,
y: 0,
items: [new Ext.Button({
cls: 'x-btn-icon-side',
icon: '/lib/images/arrow_up.png',
listeners: {
'click': function()
{
if (obj.a.sel.selection) {
var row = obj.a.sel.selection.cell[0];
var rec = obj.a.store.getAt(row);
if (row >= 1) {
obj.a.store.remove(rec);
obj.a.store.insert(row - 1, rec);
obj.a.grid.startEditing(row - 1, 0);
}
}
}
}
}), new Ext.Button({
cls: 'x-btn-icon-side',
icon: '/lib/images/arrow_down.png',
listeners: {
'click': function()
{
if (obj.a.sel.selection) {
var row = obj.a.sel.selection.cell[0];
var rec = obj.a.store.getAt(row);
var len = obj.a.store.data.items.length;
if (row < len - 1) {
obj.a.store.remove(rec);
obj.a.store.insert(row + 1, rec);
obj.a.grid.startEditing(row + 1, 0);
}
}
}
}
})]
})]
});
obj.win = new Ext.Window({
title: 'Repeating Value Editor',
layout: 'fit',
closeAction: 'hide',
border: false,
items: obj.panelAll,
width: 300,
height: 350,
resizable: false,
shadow: false,
buttonAlign: 'left',
buttons: [{
text: 'OK',
handler: function()
{
// reset the repeating field data array
obj.args.parent.dataArray = [];
for (r in obj.a.store.data.items)
obj.args.parent.dataArray[r] = obj.a.store.data.items[r].data;
obj.args.parent.setRawValue(attrValueToString(obj.args.parent.dataArray));
obj.win.hide();
}
}, {
text: 'Cancel',
handler: function()
{
obj.win.hide();
}
}]
});
obj.show = function()
{
obj.win.show();
obj.a.store.loadData(obj.args.parent.dataArray);
}
}
Теперь для моей проблемы: все это работает нормально, за исключением 7-й строки обработчика кнопки «ОК» окна (obj.args.parent.setRawValue (attrValueToString (obj.args.parent.dataArray));).
obj - это псевдоним.
obj.args.parent - псевдоним поля, открывшего окно редактора повторяющихся значений.
attrValueToString () - это функция, которая принимает двумерный массив и преобразует его в строку со специальным форматированием, чтобы ее можно было отображать в удобочитаемой и понятной форме в текстовом поле TriggerField.
Данные загружаются обратно в переменную поля dataArray, и если вы снова откроете редактор, новые данные будут включены в представление. Однако мне не удается получить какое-либо значение, отображаемое в TriggerField после его создания. Я пробовал оба obj.args.parent.setValue ('abc') и obj.args.parent.setRawValue ('abc'). Не генерируется никаких исключений, но значение, отображаемое в TriggerField, не изменяется. Я даже пытался создать пользовательскую функцию для установки значения из TriggerField - что-то вроде этого:
Ext.form.customFields['repeating'] = Ext.extend(Ext.form.customFields['repeating'], {
setFieldValue: function(value){
this.setValue(value);
}
});
Эта пользовательская функция работает, если она вызывается из TriggerField, но не когда она вызывается откуда-то еще (т.е. обработчик кнопки «ОК» окна редактора). Функция может быть успешно вызвана из любого места и не создает никаких исключений, однако, она только правильно устанавливает значение, если вызывается из TriggerField.
Настраиваемое поле отлично работает при создании его в качестве основного поля формы:
var sample = new Ext.form.customFields['repeating']({
renderTo: Ext.getBody(),
dataArray: [
{key: 'key A', value: 'value A'},
{key: 'key B', value: 'value B'},
{key: 'key C', value: 'value C'}
]
});
Я изучил документацию по API ExtJS и выполнил все возможные поиски в Google. Я нашел несколько сообщений на форуме, которые, похоже, были от людей, имеющих схожую проблему, но они так и не получили четкого ответа.
Любая помощь в этом вопросе будет очень признательна - заранее спасибо!