我有一个ExtJS(4.0.7)GridPanel,我是从商店填充的。 我在 GridPanel 列中显示的值需要具有不同的视图,具体取决于记录中的数据类型。
最终目标是,记录的 type
属性具有"双精度"或"整数"值的记录向用户显示一个滑块,用户可以调整该滑块,而一种类型的"字符串"只是呈现一些只读文本。
为此,我创建了一个自定义列。 它检查渲染器中的类型并确定要渲染的内容。
我已经让"字符串"在下面的代码中正常工作,但正在努力了解如何动态创建和呈现列中更复杂的滑块控件。
这个简化的示例只是尝试呈现一个带有日期控件的Panel
,就好像我可以做到这一点一样,我可以弄清楚滑块的其余内容。
Ext.define('MyApp.view.MyColumn', {
extend: 'Ext.grid.column.Column',
alias: ['widget.mycolumn'],
stringTemplate: new Ext.XTemplate('code to render {name} for string items'),
constructor: function(cfg){
var me = this;
me.callParent(arguments);
me.renderer = function(value, p, record) {
var data = Ext.apply({}, record.data, record.getAssociatedData());
if (data.type == "string") {
return me.renderStringFilter(data);
} else if (data.type == "double" || data.type == "integer") {
return me.renderNumericFilter(data);
} else {
log("Unknown data.type", data);
};
},
renderStringFilter: function(data) {
// this works great and does what I want
return this.stringTemplate.apply(data);
},
renderNumericFilter: function(data) {
// ***** How do I get a component I "create" to render
// ***** in it's appropriate position in the gridpanel?
// what I really want here is a slider with full behavior
// this is a placeholder for just trying to "create" something to render
var filterPanel = Ext.create('Ext.panel.Panel', {
title: 'Filters',
items: [{
xtype: 'datefield',
fieldLabel: 'date'
}],
renderTo: Ext.getBody() // this doesn't work
});
return filterPanel.html; // this doesn't work
}
});
我的问题是,如何Ext.create
组件,并将其呈现为网格面板中的列?
有几种方法可以让我看到这一点。由于网格列不是 Ext 容器,因此它不能像其他容器组件那样将 Ext 组件作为任何配置的一部分作为子组件的一部分。 需要后网格呈现逻辑才能将 Ext 组件添加到单元格。
此解决方案修改您的自定义列呈现,以便在呈现的 TD 标签上放置一个特殊的 css 类。 网格视图准备就绪后,将遍历记录,并为相应的特殊列找到自定义类。 将向找到的每个列呈现一个滑块。
下面的代码是 Sencha 示例中提供的 ext js 数组网格示例的修改版本。 修改混合了自定义列渲染器和滑块到 TD 元素的后网格渲染。
此示例仅包含对 Sencha 示例的足够修改以显示实现思想。 它缺少单独的视图和控制器逻辑。
这是从这里修改的
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.data.Model'
]);
Ext.onReady(function() {
// sample static data for the store
Ext.define('Company', {
extend: 'Ext.data.Model',
fields: ['name', 'price', 'change', 'pctChange', 'lastUpdated', 'type']
});
var myData = [
['3m Co', 71.72, 2, 0.03, '9/1/2011', 'integer'],
['Alcoa Inc', 29.01, 4, 1.47, '9/1/2011', 'string'],
['Altria Group Inc', 83.81, 6, 0.34, '9/1/2011', 'string'],
['American Express Company', 52.55, 8, 0.02, '9/1/2011', 'string'],
['American International Group, Inc.', 64.13, 2, 0.49, '9/1/2011', 'integer'],
['AT&T Inc.', 31.61, 4, -1.54, '9/1/2011', 'integer'],
['Boeing Co.', 75.43, 6, 0.71, '9/1/2011', 'string'],
['Caterpillar Inc.', 67.27, 8, 1.39, '9/1/2011', 'integer'],
['Citigroup, Inc.', 49.37, 1, 0.04, '9/1/2011', 'integer'],
['E.I. du Pont de Nemours and Company', 40.48, 3, 1.28, '9/1/2011', 'integer'],
['Exxon Mobil Corp', 68.1, 0, -0.64, '9/1/2011', 'integer'],
['General Electric Company', 34.14, 7, -0.23, '9/1/2011', 'integer']
];
// create the data store
var store = Ext.create('Ext.data.ArrayStore', {
model: 'Company',
data: myData
});
// existing template
stringTemplate = new Ext.XTemplate('code to render {name} for string items');
// custom column renderer
specialRender = function(value, metadata, record) {
var data;
data = Ext.apply({}, record.data, record.getAssociatedData());
if (data.type == "string") {
return stringTemplate.apply(data);;
} else if (data.type == "double" || data.type == "integer") {
// add a css selector to the td html class attribute we can use it after grid is ready to render the slider
metadata.tdCls = metadata.tdCls + 'slider-target';
return '';
} else {
return ("Unknown data.type");
}
};
// create the Grid
grid = Ext.create('Ext.grid.Panel', {
rowsWithSliders: {},
store: store,
stateful: true,
stateId: 'stateGrid',
columns: [{
text: 'Company',
flex: 1,
sortable: false,
dataIndex: 'name'
}, {
text: 'Price',
width: 75,
sortable: true,
renderer: 'usMoney',
dataIndex: 'price'
}, {
text: 'Change',
width: 75,
sortable: true,
dataIndex: 'change',
renderer: specialRender,
width: 200
}, {
text: '% Change',
width: 75,
sortable: true,
dataIndex: 'pctChange'
}, {
text: 'Last Updated',
width: 85,
sortable: true,
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
dataIndex: 'lastUpdated'
}],
height: 350,
width: 600,
title: 'Irm Grid Example',
renderTo: 'grid-example',
viewConfig: {
stripeRows: true
}
});
/**
* when the grid view is ready this method will find slider columns and render the slider to them
*/
onGridViewReady = function() {
var recordIdx,
colVal,
colEl;
for (recordIdx = 0; recordIdx < grid.store.getCount(); recordIdx++) {
record = grid.store.getAt(recordIdx);
sliderHolder = Ext.DomQuery.select('.slider-target', grid.view.getNode(recordIdx));
if (sliderHolder.length) {
colEl = sliderHolder[0];
// remove div generated by grid template - alternative is to use a new template in the col
colEl.innerHTML = '';
// get the value to be used in the slider from the record and column
colVal = record.get('change');
// render the slider - pass in the full record in case record data may be needed by change handlers
renderNumericFilter(colEl, colVal, record)
}
}
}
// when the grids view is ready, render sliders to it
grid.on('viewready', onGridViewReady, this);
// modification of existing method but removed from custom column
renderNumericFilter = function(el, val, record) {
var filterPanel = Ext.widget('slider', {
width: 200,
value: val,
record: record,
minValue: 0,
maxValue: 10,
renderTo: el
});
}
});
当我需要在网格列中呈现一个小图表(本质上是一个火花图)时,我做了这样的事情。这个解决方案类似于sha的解决方案,但它更健壮,并将渲染委托给正在渲染的组件而不是Column
,后者实际上没有渲染链。
一、列类:
Ext.define("MyApp.view.Column", {
extend: "Ext.grid.column.Column",
// ...
renderer: function (value, p, record) {
var container_id = Ext.id(),
container = '<div id="' + container_id + '"></div>';
Ext.create("MyApp.view.Chart", {
type: "column",
// ...
delayedRenderTo: container_id
});
return container;
}
});
请注意delayedRenderTo
配置选项。就像renderTo
一样,这将是图表组件将呈现到的元素的 DOM ID,只是它在创建时不需要存在于 DOM 中。
然后组件类:
Ext.define("MyApp.view.Chart", {
extend: "Ext.chart.Chart",
// ...
initComponent: function () {
if (this.delayedRenderTo) {
this.delayRender();
}
this.callParent();
},
delayRender: function () {
Ext.TaskManager.start({
scope: this,
interval: 100,
run: function () {
var container = Ext.fly(this.delayedRenderTo);
if (container) {
this.render(container);
return false;
} else {
return true;
}
}
});
}
});
因此,在initComponent()
期间,我们会检查延迟渲染并在必要时进行准备。否则,它将正常呈现。
delayRender()
函数本身会安排一个任务,每隔一段时间(在本例中为 100 毫秒)检查是否存在具有给定 ID 的元素——即检查列是否已呈现。如果不是,则返回 true 以重新计划任务。如果是这样,则呈现组件并返回 false 以取消任务。
我们在现场运气很好,所以我希望它也对你有用。
顺便说一下,我正在开发这个作为回答我自己关于 ExtJS 图表的问题的一部分。该线程具有我的性能测试结果。我在大多数浏览器和操作系统中以 3-4 秒的速度在网格列中渲染 168 个图表组件。我想你的滑块渲染速度会比这快得多。
尝试这样的事情:
renderNumericFilter: function () {
var id = Ext.id();
Ext.defer(function () {
Ext.widget('slider', {
renderTo: id,
width: 200,
value: 50,
increment: 10,
minValue: 0,
maxValue: 100,
});
}, 50);
return Ext.String.format('<div id="{0}"></div>', id);
}
但我必须说你想做什么 - 这听起来不对:)我不认为网格内的一堆滑块对用户来说看起来不错。