How do I attach an event handler to a panel in extJS?
Solution 1
[For anyone else reading this, I went through a fairly thorough explanation of this already here.]
You are missing a few key concepts:
click
is not a valid Panel event, so adding a click handler on a Panel will do nothing (this is the issue in most of the code you posted above).
In this code:
var menuItem1 = new Ext.Panel({
...
});
content.body
You copy-pasted from another answer, but incorrectly. content
in the other code referenced the Panel that was created -- it is a variable. In this code you created the Panel as menuItem1
but then are trying to reference it as content
?
Please re-read my previous explanation about how rendering works in the other answer I gave you. You must either add a Panel to a container that renders it, or render it directly (via the renderTo
config). If you do neither, the Panel will not show up.
Using jQuery's delegate function is not the proper approach with Ext JS components.
Solution 2
try this:
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem', listeners: { afterrender: function (comp) { var element = comp.getEl(); element.on('click', function() { alert('ok') }); } } });
Solution 3
If you want to listen to events on Ext.Elements inside of a panel, you use the element
property when calling addListener
or passing in listeners
config, instead of waiting for the afterrender
event just to set the listeners
var menuItem1 = new Ext.Panel({
id: 'panelStart',
title: 'Start',
html: 'This is the start page.',
cls:'menuItem',
listeners: {
click: {
element: 'el', // could be 'body', or any other Ext.Elements
// that are available from the component
fn: function() {}
}
}
});
Angry Dan
web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info
Updated on July 09, 2022Comments
-
Angry Dan almost 2 years
All I want to do is handle a click on an extJS panel.
I've tried all the of suggestions on this question plus all I could find elsewhere but each of them fail in the ways described below.
What is the correct syntax to add a click event handler to a extJS panel?
[Edit: For the sake of others who may find this question later, I'll add some comments inline to make this easier to decipher --@bmoeskau]
doesn't execute handler:
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem', listeners: { click: function() { alert('ok'); } } });
[Ed:
click
is not a Panel event]doesn't execute handler:
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem', listeners: { render: function(c) { c.body.on('click', function() { alert('ok'); }); } } });
[Ed: The Panel is never being rendered -- add renderTo config. Next, you'll hit a null error telling you that
c
is not a valid variable. Do you meanmenuItem1
instead?]doesn't execute handler:
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem' }); Ext.getCmp('panelStart').on('click', function() { alert('ok'); });
[Ed:
click
is not a Panel event. Also, the Panel is not yet rendered, so if you switched the callback to be on the element rather than the Component you'd get a null error.]gets error: Ext.get('panelStart') is null:
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem' }); Ext.get('panelStart').on('click', function() { alert('ok'); });
[Ed: It's not rendered, see above. Switching from
getCmp
toget
means you are switching from referencing theComponent
(which does exist, but does not have aclick
event) to referencing theElement
(which does have aclick
event, but is not yet rendered/valid).]makes the panel disappear:
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem', listeners: { 'render': { fn: function() { this.body.on('click', this.handleClick, this); }, scope: content, single: true } }, handleClick: function(e, t){ alert('ok'); } });
[Ed: The scope being passed into the callback (
content
) is not a valid ref in this code (this was copy-pasted incorrectly from another sample). Since the Panel var is created asmenuItem1
and the callback is intended to run in the panel's scope, scope var should bemenuItem1
. Also, this Panel is never rendered, see prev comments.]gives the error "Ext.fly(menuItem1.id) is null":
var menuItem1 = new Ext.Panel({ id: 'panelStart', title: 'Start', html: 'This is the start page.', cls:'menuItem' }); Ext.fly(menuItem1.id).addListener('click', Ext.getCmp(menuItem1.id) , this);
[Ed: Panel is not rendered, see above]
...put outside Ext.onReady()... gets error: Ext.getCmp('panelStart') is null
Ext.getCmp('panelStart').on('click', function() { alert('okoutside'); });
[Ed: Panel is likely not rendered at the time this code is run. Also,
click
is not a Panel event.]...put outside Ext.onReady()... gets error: Ext.get('panelStart') is null
Ext.get('panelStart').on('click', function() { alert('okoutside'); });
[Ed: See above]
...put outside Ext.onReady()... gets error: Ext.fly('panelStart') is null
Ext.fly('panelStart').on('click', function() { alert('okoutside'); });
[Ed: See above]
For the last three, I checked in Firebug and
<div id="startPanel">
exists:It works with JQuery:
So with JQuery I simply have to do this and it works:
$('body').delegate(('#panelStart'), 'click', function(){ alert('ok with jquery'); });
[Ed: This is not a good approach. It's simply delaying attaching of the handler until later, when the element actually shows up in the DOM (which could also be done via Ext btw, but would still not be the proper approach). I spelled out the correct approach, as linked in my answer below. The OP's attempts are all very close, but each is missing one or two key pieces.]
How can I attach a click handler like this with extJS?
-
Brian Moeskau over 13 yearsThis code will do nothing until the Panel is actually rendered, either via
renderTo
or by adding it to a container that renders it. Also, theafterrender
code is not really a very good approach to solving this problem. -
Gerrat over 13 yearsWell, I assumed this wasn't the complete code - only a snippet. I also think it's pretty obvious that this code won't do anything until after it's rendered...the 'afterrender' listener kind of implies that. This approach does work, but I'll certainly accept that maybe it's not a "good approach" (was just the first thing that came to mind). Perhaps you could add a comment here on why this isn't a good approach. Thanks.
-
Brian Moeskau over 13 yearsI clarified about rendering because the OP obviously does not understand this. Some of his null errors are obviously due to the Panel never being rendered, and in the code he posted in his original questions, he was attaching listeners to Panel's internal elements prior to adding the panel into a container that renders it. This code will work OK, but a better approach would be to assign the handler as a separate function on the Panel rather than an anonymous fn. continued to next comment...
-
Brian Moeskau over 13 yearsAlso, rather than handling clicks on a Panel's el directly, it's usually preferable to target a specific child, like the body. The Panel already has internal click handling, e.g. in the header bar, so you may run into issues handling clicks on the underlying el (and also you normally would not want to respond to clicks in the header/footer in app code). Most likely the OP actually wants something like
myPanel.body.on('click', ...)
where myPanel has already been rendered. Note that this could be in the render/afterrender callback too, as you show. -
Gerrat over 13 yearsOh sure...go for the whole "teach a man to fish" approach! :)
-
Angry Dan over 13 yearsgreat, thanks for all the comments, I'll work through your comments to get a solution to work in my code so I can replace the jquery approach. It makes me wonder though: why the Panel is so difficult to attach a click event to, I have been able to get quickly up to speed with handlers on buttons and grid rows with "handler..." and "listeners..." but the panel seems to be such a special case.
-
Brian Moeskau over 13 yearsThe Panel is not a special case -- it's just that the 'click' event does not make sense for the entire Panel, as a Component (it makes perfect sense for a button, grid row, or other Components). As such, it is not exposed via the Panel API. DOM events are always available on DOM nodes, but they are only made available via the Component event API when it makes sense to do so. In your case
myPanel.body.on('click', ...);
is the correct approach, just make sure the panel is rendered before doing it. -
Angry Dan over 13 yearsthis makes sense now, I was getting a
menuItem1.header is undefined
error but only when I would include menuItem1 in an accordion layout, the trick is to put themenuItem1.header.on('click',...)
AFTER the definition of the accordion layout since only then does the menuItem1 exist, thanks for clarifying this. -
Ruan Mendes over 11 years@bmoeskau The new easy way to do it is
listeners: {click:{element: 'body, fn: function(){}'}}
-
Ruan Mendes over 11 years@Gerrat This works, but there's a new simpler way to do it, see my answer