PDA

View Full Version : Q about custom events and who listens



marc123
19 Sep 2013, 2:03 PM
Hi,

I'm learning Ext 4.2.1 now from a book. About defining custom events on a model and reacting to it, it says:

"The class is responsible only for broadcasting the result of the validation. The class itself doesn't care about who may be listening, but on the outside an object is listening and reacts according to
the messages received."

I created a class A, added an event with some businesslogic and depending on the outcome it fires an event 'success' or 'fail'. Then I created an instance from that same class A, called the event on the instance and everything worked: the class fired an event, the instance of that class reacted to it.

Question:
Can an instance of another class do the same - i.e. if I create an instance of another class B (that is not firing the events) and add to that instance eventListeners that listen and react to the events fired by the class A, will this work?

I tried it and it didn't. I created an instance from class B, added eventListeners to it that listened to the events fired by class A but when I ran the page I got Ext errors. I added to class B a mixin property with value the class that class A was extending, but that didn't help.

Is listening to customevents reserved to instances of the class that fires them?
If not, how can I have class B react on events fired by class A?

Thanks,

Marc

evant
19 Sep 2013, 2:28 PM
Is listening to customevents reserved to instances of the class that fires them?


No, all events (custom or otherwise) are treated equally, anything can listen to them.

A super contrived example:


Ext.define('A', {
extend: 'Ext.Component',

doSomething: function() {
this.fireEvent('something', this);
}
});

Ext.define('B', {
extend: 'Ext.Component',

setA: function(a) {
this.a = a;
a.on('something', this.react, this);
},

react: function() {
console.log('caught something');
}
});

Ext.onReady(function() {

var a = new A();
var b = new B();
b.setA(a);
a.doSomething();

});

marc123
20 Sep 2013, 1:22 PM
Thanks for the answer!
So I made this example, the idea being 2 models, each listening and reacting to events from the other...



Ext.define('LearnExt4.model.WageSlave',{
extend : 'Ext.data.Model',
inDienst : function(){
this.addListener('fire',function(){fired();});
this.addListener('receiveBonus',function(info){receivedBonus(info);});
this.addListener('promote',function(info){promoted(info);});
console.log('John is now employed...!');
},
oversleep : function(hours){
console.log('John is now sleeping...!');
//Ext.Msg.wait('That morning...','Oooh, I am soo tired!!!',{interval: 300});
setTimeout(
function(){
Ext.Msg.hide();
this.fireEvent('oversleep',hours);
},
hours*1000
);
},
workHard : function(){
this.fireEvent('workHard',this);
console.log('John is late at work...!');

},
beatCompetitor : function(){
this.fireEvent('beatCompetitor',this);
console.log('John is beating the competitor...!');
}
});



Ext.define('LearnExt4.model.Manager',{
extend : 'Ext.data.Model',
manage : function(){
console.log('The boss manages now!');
this.addListener('oversleep',function(hours){
console.log('Wake up John!');
this.fireEvent('fire');
});
this.addListener('workHard',function(){
console.log('Good work John!');
this.fireEvent('receiveBonus',{amt:5000});
})
this.addListener('beatCompetitor',function(){
console.log('Go get \'m John!');
this.fireEvent('promote');
})
}
});




[function fired(){
Ext.Msg.alert('Woohoo!!','The sucker fired me!!!');
}

function receivedBonus(data){
Ext.Msg.alert('Woohoo!!','I received a bonus of &Eur;'+ data.amt+',-!!');
}

function promoted(reason){
Ext.Msg.alert('Woohoo!!','The sucker promoted me!!!');
}




[var John = Ext.create('LearnExt4.model.WageSlave',{});
var Boss = Ext.create('LearnExt4.model.Manager');
John.inDienst();
Boss.manage();
John.oversleep(2);


So the idea being that whenJohn is employed, he is listening for events from his boss who in turn listens to events from John. Both respond to events in their own way. We let John oversleep (2hours) and:

the boss hears this via this.addListener('oversleep'...)
the boss fires event 'fire'
John hears this and responds by calling function fired().

In the console I only see the following messages:
'The boss manages now!'

'John is now employed...!'
'John is now sleeping...!'
and after the timeout
TypeError: me.cfg is undefined

ext-all-dev.js (line 127332)














instead of the Boss responding to John oversleeping, firing an event, John reacting etc...

Why aren't the events firing as I expect?

Thanks,

Marc

marc123
20 Sep 2013, 1:48 PM
Hi Evan,
You're setting the listener on the same object (a) that fired the event:

b.setA(a);So a.doSomething() is causing a to do this.react(this)... Looks like a is talking to itself... ???

evant
20 Sep 2013, 2:26 PM
Right, that's how the pattern works. If the object fires an event, then you need to listen to the event on the object that fires it.

When doSomething is called, it fires an event. B listens to that event, and calls it's own method (react) to handle it.

B doesn't need to know anything about A, only that it fires some event. Note that the call to doSomething() is not called from B, but from some external code.

marc123
20 Sep 2013, 2:30 PM
fixed this, see my next post...
and also I had to put the calls to John and Boss inside the onReady method else the Ext.Msg.alert() would try to render to an non-existing Ext.getBody(). It cannot find it since the page has not been rendered yet...

marc123
20 Sep 2013, 2:39 PM
This is what the book says about events (the observer pattern?):
"Events are the way we can execute actions when something is happening; as we
can see in the previous example the Employee class is responsible only for
broadcasting the result of the validation. The class itself doesn't care about who
may be listening, but on the outside an object is listening and reacts according to
the messages received."
So the class defines when events are fired but an instance of the class has to react to them...

code:


Ext.define('MyApp.users.Employee',{
//...
login: function(usr,pwd){
var me = this;
Ext.Msg.wait('Please wait','Loading...',{
interval: 300
});
//faking the server response
setTimeout(function(){
Ext.Msg.hide();
me.attempts++;
if(usr === 'john' &&pwd === '123'){
me.fireEvent("success",me);
}else{
me.fireEvent("fail",me.attempts);
}
},3000);
}
});
var employee = Ext.create("MyApp.users.Employee");

employee.on("success",function(user){
Ext.Msg.alert("Success","Welcome to our application");
});

employee.addListener("fail",function(attempts){
Ext.Msg.alert("Error","Wrong credentials! "+attempts+" attempts");
});


Marc

evant
20 Sep 2013, 2:50 PM
No. A class defines what events are fired. An instance actually fires the events.

Anything can listen to an event.

Here's a more useful example:



Ext.require('*');

Ext.onReady(function() {

var text = 'Foo';

var p1 = new Ext.panel.Panel({
region: 'west',
width: 200,
title: text
});

var p2 = new Ext.panel.Panel({
region: 'center',
items: {
xtype: 'button',
text: text
}
});

var p3 = new Ext.panel.Panel({
region: 'east',
width: 300,
items: [{
xtype: 'textfield',
fieldLabel: 'Title',
labelWidth: 60,
value: text
}, {
xtype: 'button',
text: 'Change',
handler: function() {
var val = p3.down('textfield').getValue();
p1.setTitle(val);
}
}]
});

new Ext.container.Viewport({
layout: 'border',
items: [p1, p2, p3]
});

// Listen to when the title changes on p1
p1.on('titlechange', function(p, newTitle) {
// Find the button, set the text so they match
p2.down('button').setText(newTitle);
});

});


Clicking the button changes the title. We listen to that titlechange event on that panel, so we can update the title on the other button.