What I would suggest you consider is extending List and add in buttons similar to the onItemDisclosure feature. With the item disclosure, you can have a button dropped in along the right edge of the list item and trap that event. You may wish to have your own custom button, or even an array of buttons. I am including an extension that I did of list to add an array of 2 extra buttons in addition to the itemDisclosure button, giving me a set of 3 buttons that i can trap independently of the item click itself.
Screen shot 2011-09-12 at 12.14.03 PM.jpg
Example extension: so, what i have added is an analyze button and a statuschange button that raises those events....
Code:
Ext.namespace('Ext.ux');
/**
* @class Ext.form.SpecialsList
* @extends Ext.List
* <p>Specialized list for specials that includes analytics link as well as status change link {@link Ext.SpecialsList}.</p>
* @xtype datepickerfield
*/
Ext.ux.SpecialsList = Ext.extend(Ext.List, {
preventSelectionOnStatusChange: true,
preventSelectionOnAnalysis: true,
// @private
initComponent : function() {
var memberFnsCombo = {};
if (Ext.isArray(this.itemTpl)) {
this.itemTpl = this.itemTpl.join('');
} else if (this.itemTpl && this.itemTpl.html) {
Ext.apply(memberFnsCombo, this.itemTpl.initialConfig);
this.itemTpl = this.itemTpl.html;
}
if (!Ext.isDefined(this.itemTpl)) {
throw new Error("Ext.List: itemTpl is a required configuration.");
}
// this check is not enitrely fool proof, does not account for spaces or multiple classes
// if the check is done without "s then things like x-list-item-entity would throw exceptions that shouldn't have.
if (this.itemTpl && this.itemTpl.indexOf("\"x-list-item\"") !== -1) {
throw new Error("Ext.List: Using a CSS class of x-list-item within your own tpl will break Ext.Lists. Remove the x-list-item from the tpl/itemTpl");
}
this.tpl = '<tpl for="."><div class="x-list-item ' + this.itemCls + '"><div class="x-list-item-body">' + this.itemTpl + '</div>';
this.tpl += '<div class="x-list-status"></div>';
this.tpl += '<div class="x-list-analysis"></div>';
if (this.onItemDisclosure) {
this.tpl += '<div class="x-list-disclosure"></div>';
}
this.tpl += '</div></tpl>';
this.tpl = new Ext.XTemplate(this.tpl, memberFnsCombo);
if (this.grouped) {
this.listItemTpl = this.tpl;
if (Ext.isString(this.listItemTpl) || Ext.isArray(this.listItemTpl)) {
// memberFns will go away after removal of tpl configuration for itemTpl
// this copies memberFns by storing the original configuration.
this.listItemTpl = new Ext.XTemplate(this.listItemTpl, memberFnsCombo);
}
if (Ext.isString(this.groupTpl) || Ext.isArray(this.groupTpl)) {
this.tpl = new Ext.XTemplate(this.groupTpl);
}
}
else {
this.indexBar = false;
}
if (this.scroll !== false) {
this.scroll = {
direction: 'vertical',
useIndicators: !this.indexBar
};
}
Ext.List.superclass.initComponent.call(this);
if (this.onItemDisclosure) {
// disclosure can be a function that will be called when
// you tap the disclosure button
if (Ext.isFunction(this.onItemDisclosure)) {
this.onItemDisclosure = {
scope: this,
handler: this.onItemDisclosure
};
}
}
this.on('deactivate', this.onDeactivate, this);
this.addEvents(
/**
* @event disclose
* Fires when the user taps the disclosure icon on an item
* @param {Ext.data.Record} record The record associated with the item
* @param {Ext.Element} node The wrapping element of this node
* @param {Number} index The index of this list item
* @param {Ext.util.Event} e The tap event that caused this disclose to fire
*/
'disclose',
/**
* @event update
* Fires whenever the contents of the List is updated.
* @param {Ext.List} list This list
*/
'update',
'analyze',
'statuschange'
);
},
afterRender : function() {
Ext.ux.SpecialsList.superclass.afterRender.call(this);
this.mon(this.getTargetEl(), 'singletap', this.handleStatusChange, this, {delegate: '.x-list-status'});
this.mon(this.getTargetEl(), 'singletap', this.handleAnalysis, this, {delegate: '.x-list-analysis'});
if (this.onItemDisclosure) {
this.mon(this.getTargetEl(), 'doubletap', this.handleItemDisclosure, this);
}
},
//@private
handleStatusChange : function(e, t) {
var node = this.findItemByChild(t),
record, index;
if (node) {
record = this.getRecord(node);
index = this.indexOf(node);
if (this.preventSelectionOnStatusChange) {
e.stopEvent();
}
this.fireEvent('statuschange', record, node, index, e);
}
},
//@private
handleAnalysis : function(e, t) {
var node = this.findItemByChild(t),
record, index;
if (node) {
record = this.getRecord(node);
index = this.indexOf(node);
if (this.preventSelectionOnAnalysis) {
e.stopEvent();
}
this.fireEvent('analyze', record, node, index, e);
}
}
});
// register xtype
Ext.reg('specialslist', Ext.ux.SpecialsList);
So, here is an example of using this extension inline... Notice my itemTpl has no buttons in it, Those are created by the control extension and the events that are raised are done from that extension as well.
Code:
{ cls: 'ts-list',
xtype: 'specialslist',
width: '100%',
scroll: 'vertical',
itemTpl: '<table class="ts-list-specials-row-text">' +
'<tr>' +
'<td rowspan="5">' +
'<img class="ts-list-specials-row-image" src="{image}" />' +
'</td>' +
'<td class="ts-list-specials-row-label">' +
'{title}' +
'</td>' +
'</tr>' +
'<tr>' +
'<td><p>' +
'{venueName}' +
'</p></td>' +
'</tr>' +
'<tr>' +
'<td><p>' +
'{subtitle}' +
'</p></td>' +
'</tr>' +
'<tr>' +
'<td><p>' +
'{detail}' +
'</p></td>' +
'</tr>' +
'<tr valign="bottom">' +
'<td>' +
'{startTime} - {endTime}' +
'</td>' +
'</tr>' +
'<tr>' +
'<td class="ts-list-specials-status-{status}" rowspan="2"><p>' +
'{status}' +
'</p></td>' +
'<td>' +
'{startDate} - {endDate}' +
'</td>' +
'</tr>' +
'</table>',
cls: 'ts-list',
onItemDisclosure: function(record, btn, index) {
vm.activateItem('Detail');
Ext.getCmp('Detail').load(record);
// this would be uncommented in lieu of the form.load call if we activate the bindContext logic
// select the record in the store, and load the detail view
{modelPropName: field.name});
},
// bind to places store
store: '${specials}',
listeners: {
'update': function(list) {
list.setLoading(false);
},
'analyze': function(record, node, index, evt) {
console.log('analyze button clicked');
},
'statuschange': function(record, node, index, evt) {
console.log('statuschange clicked');
}
}
}
]
}