Работая в ExtJS 3.4, мне нужно показать некоторые значения в нескольких строках (макет формы). Каждая строка выглядит так:
<label> <field> <unit of measure>
Где <unit of measure>
- это DisplayField
с нередактируемым вручную текстом, указывающим единицу измерения (например, литры, метры, ...).
Мне нужно добавить механизм для переключения между единицами измерения, например. кнопка. В идеале я хотел бы щелкнуть эту кнопку, изменить одно значение (или вызвать только один метод установки) и увидеть новое значение в частях моего интерфейса <unit of measure>
. Другими словами, мне бы хотелось, чтобы мне не приходилось сохранять и циклически перебирать серию ссылок на несколько объектов DisplayField
.
До сих пор я пытался создать экземпляр и сохранить ссылку на один DisplayField
и вставить его в несколько строк, чтобы я мог вызвать field.setValue(...)
, например:
var dispF = new Ext.form.DisplayField({
value:'liters'
});
var row1 = new Ext.form.CompositeField({
...
items: [<some numberfield 1>, dispF]
...
});
var row2 = new Ext.form.CompositeField({
...
items: [<some numberfield 2>, dispF]
...
});
//Calling this by some means
dispF.setValue('m^3');
Однако dispF
будет отображаться только на последнем созданном элементе, который его использует (в данном случае row2
).
Я также пробовал следующее:
var t = 'liters';
var dispF = {
xtype:'displayfield',
value:t
};
var row1 = new Ext.form.CompositeField({
...
items: [<some numberfield 1>, dispF]
...
});
var row2 = new Ext.form.CompositeField({
...
items: [<some numberfield 2>, dispF]
...
});
...
//Calling this by some means
t='m^3';
В этом случае «литры» отображаются в правильном положении для всех строк, но не меняются на «m ^ 3».
Я бы не хотел использовать для этого сетку.
Обработка каждого поля вручную может быть немного сложной, так как строк много, и на самом деле они могут содержать более одного поля и группы единиц измерения, в то время как их хранение в массивах затруднит чтение кода тем, кто пришел после (code здесь необходимо учитывать удобочитаемость).
Есть ли способ обновить DisplayField в каждой строке с помощью выполнение только одной операции (например, назначение, вызов setValue (), ...) вместо того, чтобы объявлять и создавать экземпляр DisplayField для каждой строки, а затем вызывать setValue () для каждой из них?
Следующее решение может вам помочь. Отличие заключается в том, что значения изменяются с помощью вызова одна пользовательская функция, а не с помощью одна операция.
Но с этим решением вам не нужно хранить ссылку для каждого объекта displayfield
или хранить их в массиве.
Шаги в решении: создать подкласс displayfield
и определяемую пользователем функцию:
Ext.onReady(function(){
// Class definition.
TestDisplayField = Ext.extend(Ext.form.DisplayField, {
constructor: function(config) {
TestDisplayField.superclass.constructor.call(this, config);
},
});
Ext.reg('testdisplayfield', TestDisplayField);
// Global setter function.
function setTestDisplayFieldValues(container, value, xtype) {
var items = container.items;
for (var i = 0; i < items.length; i++) {
var component = items.get(i);
if (Ext.isDefined(component.items)) {
setTestDisplayFieldValues(component, value, xtype)
} else {
if (component.xtype == xtype) {
component.setValue(value);
}
}
}
};
// Components.
// Here are 'displayfield' and 'tesdisplayfield' components just for test.
var row1 = new Ext.form.CompositeField({
items: [
{xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
{xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
{xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100},
{xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100}
]
});
var row2 = new Ext.form.CompositeField({
items: [
{xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
{xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
{xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100},
{xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100}
]
});
// Form
Ext.create(
{
xtype: 'form',
id: 'testform',
renderTo: Ext.getBody(),
title: 'Image',
width: 600,
height: 300,
layout: 'vbox',
items: [
row1,
row2
],
buttons: [
{
text: 'Set value',
handler: function(button) {
// Change the values of all 'testdisplayfield' components.
// Here you can use 'displayfield' as xtype if all you components are 'displayfield' and must be changed.
// In this case it's not necessary to define 'TestDisplayField' class.
setTestDisplayFieldValues(Ext.getCmp('testform'), 'm^3', 'testdisplayfield');
}
}
]
});
});
Примечания:
Протестировано с ExtJS 3.4
Я подумал о добавлении прослушивателя onRender в конфигурацию DisplayField, чтобы добавить каждое поле в массив, а затем циклически перебирать этот массив, когда мне нужно изменить значения (таким образом, массив гарантированно будет содержать только элементы, экземпляры которых созданы из этой конфигурации). Однако это звучит тяжело с точки зрения слушателей, которых нужно было бы уволить только один раз. Предлагаемое решение кажется более компактным, и даже при рекурсивном исследовании DOM-дерева оно не выглядит слишком тяжелым (плюс, пользователь не собирается менять единицу измерения каждые полсекунды). Принято как правильный ответ. Спасибо.