PDA

View Full Version : Apply listener to dynamic BoxComponent?



feyyaz
4 Aug 2009, 5:07 AM
hi guys,

until now i had many problems which i could solve by searching the forums. but this time no luck. i think it should be easy, but i cant see it. so here is my problem:

i am creating dynamicaly a BoxComponent to display a image which should react on a click.

here are my tried approches, the BoxComponent is than added to a panel with hbox layout i leave the code for the panel creation out, because if i exchange Ext.BoxComponent with Ext.Button, everything is working like wanted, but i don't want the button wrapper/style around my image.

1.


var img=new Ext.BoxComponent({
id:'myImage',
autoEl:{
tag:'img',
src:'images/img.gif'
}
});

img.on('click',function() {
alert('clicked');
});

2.


var img=new Ext.BoxComponent({
id:'myImage',
autoEl:{
tag:'img',
src:'images/img.gif'
},
listeners:{
click: function() {
alert('clicked');
}
}
});
the only way i get it to work is


var img=new Ext.BoxComponent({
id:'myImage',
autoEl:{
tag:'img',
src:'images/img.gif',
onclick:'alert("clicked")'
}
});
but this is not what i want because in this solution i am in a different scope and it's not the Ext way.

hope someone can help me out with that,
feyyaz

Condor
4 Aug 2009, 5:13 AM
BoxComponent doesn't have a 'click' event. Only the Ext.Element it contains has a 'click' event, but you'll have to wait until it is created to attach the listener, e.g.

var img=new Ext.BoxComponent({
id:'myImage',
autoEl:{
tag:'img',
src:'images/img.gif'
},
listeners:{
render: function(c) {
c.getEl().on('click', function(){
alert('clicked');
});
}
}
});

feyyaz
4 Aug 2009, 5:22 AM
Wow... works like a charm, thank you very much - that was fast.

Animal
4 Aug 2009, 5:29 AM
There's GOT to be a way we can get them to stop posting this question!

Condor
4 Aug 2009, 5:56 AM
I would be for a domEvents config option:

Ext.override(Ext.Component, {
initEvents : function(){
if(this.keys){
this.getKeyMap();
}
if(this.draggable){
this.initDraggable();
}
if(this.domEvents){
this.relayEvents(this.el, this.domEvents);
}
}
});
so you can use:

var img = new Ext.BoxComponent({
id: 'myImage',
autoEl: {
tag: 'img',
src: 'images/img.gif'
},
domEvents: ['click'],
listeners:{
click: function(){
alert('clicked');
}
}
});

Animal
4 Aug 2009, 6:18 AM
Yes, that would be great.

Didn't I add an FR for that and Aaron responded very quickly with a rejection?

Animal
4 Aug 2009, 6:20 AM
http://extjs.com/forum/showthread.php?t=64336

Eric24
5 Nov 2009, 10:14 PM
Condor--Maybe a dumb question, but for my education, would this be a good place (the 'click' event on the img element) to use 'mon' instead of 'on', or is that somehow made unnecessary by virtue of the BoxComponent 'containing' to img tag?

Condor
6 Nov 2009, 12:02 AM
No, using 'mon' instead of 'on' would indeed make sure the element listeners are purged when destroying the component.

Unfortunately there is not relayEvents method that uses 'mon' instead of 'on', so you would need to write that yourself.

Eric24
6 Nov 2009, 6:29 AM
Hmmm. Then do I need to an 'un' when destroying the BoxComponent?

Animal
6 Nov 2009, 6:33 AM
Component.destroy removes all listeners from its main Element.

Eric24
6 Nov 2009, 6:39 AM
Thanks for the info. To be clear, you say "main Element", so that would apply in this particular scenario (where the Box contains a single img), but what if I added a button or second image to the Box and attached a listener to it--from your comment, it sounds like I would need to do the 'un' on that listener?

BTW, do you know of anything I could read that would make clear the scenarios when/what I need to "clean up" when destroying Ext components (or does that question just answer itself, in that "you never need to clean up after an Ext component")? I've been trying to come up with some good coding practices that prevent memory/resource leaks, but the area of when/what to clean up is a bit fuzzy; for example, if Component.destroy removes all listeners, is there anything that needs to be cleaned up, and if not, when is 'mon' useful?

Animal
6 Nov 2009, 6:54 AM
Yes, from the getEl() element - the main element of the Component.

If you had listeners on descendant elements, they would not be purged.

However there is a global option in the latest code, Ext.enableNestedListenerRemoval which causes Element.remove to cascade down all descendant elements and remove listeners.

IMHO, that should be an optional parameter to Element.remove, and by extension also to Container.destroy. Having it globally all or nothing is bad.

hendricd
6 Nov 2009, 8:10 AM
I'm using this variant successfully now: :-?




Ext.override( Ext.Component , {

afterRender : function(){

if(Ext.isObject(this.boundEvents)){
Ext.iterate(this.boundEvents, function(ref, listeners){

if(ref = this[ref]){
Ext.each([].concat(listeners), function(listener){
this.mon.apply(this,[ref].concat(listener))
},this);
}
}, this);
delete this.boundEvents;
}
}
});

Thus:



var img=new Ext.BoxComponent({
id:'myImage',
autoEl:{
tag:'img',
src:'images/img.gif'
},
boundEvents:
{el : [ //late binding by member name eg. this['el']
['click', function(e) { alert('clicked');}, null, {stopEvent: true}], //standard array of args

//or listener object:
{load: function(e) {alert('loaded'); }, single : true }
]
}

});Great way to build light-weight Components (without extending classes) :-?

mberrie
3 Apr 2011, 8:13 AM
Resurrection!

I modified the code to allow for referencing nested properties, e.g. 'tools.toggle' in an Ext.Panel.

I wonder whether the issue of DOM event listeners has been addressed in ExtJs 4? Maybe as a Mixin?




Ext.override(Ext.Component, {

afterRender : function() {

if (Ext.isObject(this.boundEvents)) {
Ext.iterate(this.boundEvents, function(ref, listeners) {

if (ref = this.resolve(ref)) {
Ext.each([].concat(listeners), function(listener) {
this.mon.apply(this, [ref].concat(listener))
}, this);
}
}, this);
delete this.boundEvents;
}
},

/**
* Resolves a string reference to an object property and returns the actual
* property value/object.
* The reference String supports nested properties via dot-notation.
*
* @param {String} ref the property reference String
* @param {object} obj (optional) the object that the reference string is applied to - defaults to <code>this</code>
*/
resolve : function(ref, obj) {
obj = obj || this;
var tokens = ref.split('.', 2);
return tokens.length <= 1 ?
obj[ref] :
this.resolve(tokens[1], obj[tokens[0]]);
}
});