Em uma aplicação web tudo se resume a eventos. As ações sempre acontecem quando um usuário clica em um botão, coloca foco em um campo, ativa uma aba de um painel, etc… Graças a classe Ext.util.Observable o Ext proporciona uma forma única de gerenciar os eventos da aplicação. Veremos nesse post como o sistema de eventos funciona, e todos os segredos para você otimizar seu código no que é a coluna fundamental de sua aplicação, a interação do usuário com seu sistema..
Fundamentos básicos
Os eventos de um componente estão listados em uma seção especial da documentação, ao final de cada página. Não existem local melhor para se ter conhecimento de um evento do que lá. Conforme aprendemos mais sobre o framework podemos perceber que existe certa padronização no nome dos eventos, e que sua descrição é  sempre muito intuitiva. Quando sou perguntando “Dá para executar tal rotina quando o usuário fizer essa ação” eu logo tento recordar se “essa ação” tem algum evento disponÃvel ou similar. A partir daà passo para a documentação onde posso verificar toda a especificação do evento.
Uma coisa que temos que ter em mente é que os eventos do Ext são sempre disparados. Quando você expande um painel o evento “expand” é disparado mesmo que você não tenha adicionado nenhum listener a ele. Adiciono aqui um novo termo ao post: listener. Denominamos de listener uma função ouvinte. Como o nome diz, ela “ouve” (monitora) o evento, para que quando ele for disparado o ouvinte seja executado.
Como utilizar os eventos
A forma mais fácil, e aclamada por outros frameworks, de associar um evento é através do método .on. Toda classe que estende de Ext.util.Observable possui esse método, ou seja, grande parte do framework incluindo todos os componentes. Esse método é na verdade um atalho, o original é addListener. A documentação prevê 2 parâmetros obrigatórios e 2 opcionais. O primeiro é o nome do evento ao qual o listener será adicionado. O segundo uma referência para a função listener, comumente usamos o conceito de funções anônimas para esse parâmetro. O terceiro parâmetro indica o escopo de execução do listener. Por padrão o escopo aponta para o componente ao qual o listener está associado, se você deseja alterar pode fazê-lo através desse parâmetro. O último são parâmetros adicionais, que adiciona o listener caracterÃsticas como: executar somente uma vez, executar com atraso (delay), executar com buffer, executar somente quando a ação ocorrer em determinado component.
/**
* Básico
*/
painelCentro.on("expand",function()
{
alert("expandiu");
});
/**
* evento + handler + escopo + executar somente uma vez e depois ser removido
*/
painelCentro.on(
"render"
,onPainelCentroRender
,painelCentro
,{
single:true
}
);
/**
* executar o handler uma vez só. Se em menos de 500ms o listener for disparado
* novamente a antiga execução é descartada e uma nova é criada
*/
formCadastro.on(
'afterlayout'
,onFormCadastroAfterLayout
,formCadastro
,{
single : true
,buffer : 500
}
);
/**
* Só executa quando um componente for adicionado no painelCentro. Evita
* event bubbling
*/
painelCentro.on(
"add"
,onPainelCentroAdd
,painelCentro,
{
target:painelCentro
}
);
/**
* Informando um escopo (geralmente usado em classes)
*/
Relatorio = Ext.extend(Ext.grid.GridPanel,{
initComponent: function()
{
//TODO: criar store, colunas e toda configuração do grid
//Informando evento, associando uma função, e indicando
//seu escopo como o grid
this.store.on('load', this._onStoreLoad , this);
}
,_onStoreLoad: function( store )
{
/* this é o grid, não o store. Alteramos o escopo dessa função.
* É uma boa prática manter o escopo sempre na classe para não
* criar confusão no código. A maioria dos eventos recebe o
* próprio componente ao qual o evento está associado por
* parâmetro.*/
alert(this);
}
});
Ext permite especificar listeners de um evento de mais outras duas formas, ambas para associação de múltiplos eventos. A primeira você informa os eventos e as configurações, que nesse caso serão válidas para todos eles.
/*
* Vários eventos no mesmo componente, com a configuração
* scope sendo válida para todos eles
*/
meuGrid.on({
scope : this
,'render' : this.onGridRender
,'rowclick' : this.onGridRowClick
,'hide' : this.onGridHide
});
A segunda permite especificar configurações individuais para cada evento, ainda podendo associar vários de uma vez só.
/*
* Vários eventos no mesmo componente, cada um com
* sua configuração
*/
meuGrid.on({
'render' : {
scope : this
,delay : 500
,fn : this.onGridRender
}
,'rowclick' : {
scope : this
,buffer : 500
,fn : this.onGridRowClick
}
,'hide' : {
scope : this
,single : true
,fn : this.onGridHide
}
});
E ainda existe ainda uma outra forma de associar um evento, através da configuração listeners de cada componente. A forma de especificar segue o modelo do método .on, porém é realizado na própria estrutura do componente. A diferença desse tipo de associação do que a outra é que nessa os listener são adicionados logo no inÃcio, antes de qualquer outro adicionado pelo framework Ext.
new Ext.Viewport({
layout : 'border'
,items : [{
xtype : 'panel'
,region : 'north'
,listeners : {
scope : this
,'render' : this.onPanelNorteRender
}
},{
xtype :'tabpanel'
,listeners : {
'tabchange': {
delay : 500
,fn : this.onTabChange
}
,'afterlayout':{
buffer : 200
,fn : this.onTabPanelAfterLayout
}
}
}]
})
Como funciona?
Em 3 passos posso lhe explicar como um evento é criado no Ext:
- Componente estende diretamente ou indiretamente de Ext.util.Observable
//Panel extende de Container, que extende de boxComponent, //que extende de Component, que extende de Observable Ext.Panel = Ext.extend(Ext.Container, {}); - Utilizar o método addEvents para disponibilizar os eventos
initComponent : function() { Ext.Panel.superclass.initComponent.call(this); this.addEvents( 'bodyresize', 'titlechange', 'iconchange', 'collapse', 'expand', 'beforecollapse', 'beforeexpand', 'beforeclose', 'close', 'activate', 'deactivate' ); } - Disparar o evento passando quantos parâmetros quiser
setTitle : function(title, iconCls) { //TODO: altera o tÃtulo /* Evento titlechange sendo disparado passando como parâmetros * a referência do painel, e o titulo novo. Qualquer listener * associado ao evento será executado */ this.fireEvent('titlechange', this, title); }
É assim que o Ext faz, e é da mesma forma que você pode implementar seus próprios eventos nas suas classes
Extra
Segue alguns tópicos extra para acrescentar ainda mais aos seus novos conhecimentos.
Event Bubbling
A partir da versão 3.0 foi criado o mesmo conceito que existe a muito tempo no Javascript. Usando JS nativo, se você criar uma função no evento  ”onClick” da tag body, qualquer elemento clicado dentro da página irá disparar o evento, porque ele se propaga pela cadeia de elementos. O mesmo acontece nos métodos add e remove da classe Ext.Container e suas filhas. Isso graças a adição do código abaixo:
this.enableBubble('add', 'remove');
Isso pode lhe causar algumas dores de cabeça, então lembre-se da configuração target comentada anteriormente para evitar que isso ocorra.
Single: true, boa prática
Um componente só é renderizado uma única vez, logo se você adicionar um listener ao evento render ele será executado uma única vez. Apesar disso o listener não é desassociado do evento, somente quando o componente é destruÃdo. Sendo assim se faz uma boa prática informar single:true para eventos que você quer que sejam executadas uma única vez, porque eles são disparados e logo em seguida removidos.
Remover um listener
Assim como existe o método .on para adicionar um listener, existe o método .un (ou removeListener). Tome atenção com o escopo: se ao associar você informou um escopo para o listener, ao remover também deve informar.
this.store.un('load', this._onStoreLoad , this);
Concluindo
É de extrema importância a qualquer programador Ext dominar totalmente os conceitos pertinentes a classe Ext.util.Observable. Sendo eventos a chave das aplicações web podemos ter um grande diferencial no código ao conhecer melhor como associar um evento, as várias formas de associar, as configurações adicionais representa, etc…
Está por vir um post sobre programação orientada a eventos, aonde irei pegar todos os conceitos sobre classes já postados aqui no extdesenv, e adicionarei eventos personalizados, criando assim um padrão de programação muito bacana.
Qualquer dúvida sabem aonde me encontrar! Forte abraço e até a próxima!
Posts relacionados:






Parabens cara….
Este post é fundamental para elucidar algumas incognitas que vão aparecendo durante o aprendizado/desenvolvimento.
Valew mesmo !!
Bruno, mais um excelente post. Eventos no extjs é uma das coisas mais úteis e é fundamental saber como funciona.
Parabéns.
Bruno, Simplesmente Show seu novo post.
Aprendi muito com ele.
Não sabia que podia usar varios eventos assim ao mesmo tempo.
meuGrid.on({
scope : this
,’render’ : this.onGridRender
,’rowclick’ : this.onGridRowClick
,’hide’ : this.onGridHide
});
Cara apartir de agora vou começar estudar essa class observable entre outras, com certeza ela nos esclarecerá muitas duvidas.
Parabéns.
Parabéns pelo seu trabalho, tenha certeza que seus posts estão sendo úteis a muitos desenvolvedores que estão passando a utilizar este framework.