Jul
13

Utilização de Custom Events para transportar informação entre classes

A 11 de Março elaborei um post relevante sobre a utilização de eventos aquando da criação de componentes fracamente acoplados. Em resumo, o que se pretendia era eliminar a utilização do “parent” na comunicação entre classes. A solução exemplificada consistia em detectar um clique numa opção de um menu e lançar um evento a “informar” a necessidade de mudança de secção. A classe acima teria que escutar esse evento, e reagir fazendo então a mudança de secção .

Aconselho vivamente a leitura desse post para facilitar a compreensão deste.

Após esse post, uma das principais questões que me fizeram, foi “e como transportar dados no evento?”.

Exemplo

Imaginemos um site com a seguinte estrutura:

  • Stage
  • Stage.seccaoDeProdutos
  • Stage.seccaoDeProdutos.listagem
  • Stage.seccaoDeProdutos.listagem.itemProduto1
  • Stage.seccaoDeProdutos.listagem.itemProduto2
  • Stage.seccaoDeProdutos.listagem.itemProduto[n]
  • Stage.seccaoDeProdutos.produtoDetalhe

Pretende-se que a classe Listagem detecte cliques nos produtos. Sempre que há um clique num produto, a classe SeccaoDeProdutos deve ser informada e reagir, removendo a listagem, e mostrando o ProdutoDetalhe com os dados do produto clicado.
Graças ao post anterior, já sabemos como resolver a primeira metade deste problema (reagir ao clique, remover a listagem, e mostrar o ProdutoDetalhe), como se demonstra adiante:

Reagir ao clique

Exemplo do Listagem.as

// Considerando que listaDeProdutos é uma matriz com instâncias da
// classe Produto (id:Number, designacao:String, descricao:String, foto:String)
for (var i:Number=0; listaDeProdutos.length>i; ++i)
{
var p:ItemProduto=new ItemProduto(); // Criar um ItemProduto
p.dados=listaDeProdutos[i]; // Colocar os dados do produto dentro do ItemProduto
addChild (p) // Colocar o ItemProduto no ecrã
p.addEventListener(MouseEvent.CLICK, produtoClickHandler);  // Detectar os cliques no itemProduto
}

private function produtoClickHandler(ev:MouseEvent):void
{
dispatchEvent(new Event('produtoClick'));
}

No SeccaoDeProdutos.as:

var l:Listagem=new Listagem();
addChild(l);
l.addEventListener('produtoClick', listagemProdutoClickHandler);

private function listagemProdutoClickHandler(ev:Event):void
{
trace('Agora bastaria remover o listagem, e instanciar o ProdutoDetalhe com os dados do produto clicado');
trace('Mas... qual é o produto clicado????')
}

Transportar dados

Entramos agora na segunda parte do problema: como entregar à classe SeccaoDeProdutos o produto que foi clicado?

A solução consiste em criar um Custom Event: uma classe nossa que estende a classe Event, e pode por isso levar mais propriedades – sendo assim usada para transportar informação de um lado para o outro.

Na solução acima, no produtoClickHandler, fazemos dispatchEvent(new Event(‘produtoClick’)); Se interpretarmos esta linha de código, vemos que está a ser lançado um evento do tipo “Event”, com o tipo “produtoClick”. É aqui que queremos lançar um evento nosso, que vamos ter que criar previamente, como se explica adiante.

Criar um Custom Event

Criar um Custom Event não é mais que criar uma classe que estende a classe Event. Vamos assim criar a nossa classe ProdutoEvent:

ProdutoEvent.as:

package
{
import flash.events.Event;
public class ProdutoEvent extends Event
{
public function ProdutoEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

Transportar dados no Custom Event

O código acima é o suficiente para definir um novo evento. Porém, ainda não chega para o nosso caso: queremos que o nosso evento possa transportar dados. Assim, a solução passa simplesmente por adicionar uma propriedade pública ao nosso evento:

ProdutoEvent.as:

package
{
import flash.events.Event;
public class ProdutoEvent extends Event
{
public var produto:Produto;
public function ProdutoEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

Agora que temos o evento criado, já o podemos usar. Alteramos assim o código do Listagem.as :

Listagem.as:

private function produtoClickHandler(event:MouseEvent):void
{
var produtoEvent:ProdutoEvent=new ProdutoEvent('produtoClick');
produtoEvent.produto= (event.currentTarget as ItemProduto).dados   ;     // Vamos colocar dentro do nosso evento (ev.produto) os dados que vamos buscar ao ItemProduto clicado (ev.currentTarget as ItemProduto), que estão na propriedade dados, como vimos no código inicial
dispatchEvent(produtoEvent);
}

Agora na classe SeccaoDeProdutos.as, temos que apanhar o tipo certo de evento no handler, e já conseguimos aceder aos dados transportados. Basta fazer a seguinte alteração:

SeccaoDeProdutos.as:

private function listagemProdutoClickHandler(ev:ProdutoEvent):void
{
trace('Agora bastaria remover o listagem, e instanciar o ProdutoDetalhe com os dados do produto clicado');
trace('O produto clicado foi: ' + ev.produto.designacao + ' TARAAAAM!');
}

Temos com isto um evento que pode carregar dentro de si dados preenchidos na classe que o lança, para que possam ser usados pela classe que o apanha.

Criação de tipos no Custom Event

O código acima já resolve o problema, mas pode ser melhorado de forma a evitar a string “produtoClick”. O ideal seria conseguirmos obter o mesmo comportamento que temos com a classe MouseEvent: fazermos algo como MouseEvent.CLICK em vez de escrevermos à mão “produtoClick”.

Para isso basta criarmos dentro da classe ProdutoEvent constantes estáticas do tipo String, uma para cada tipo de evento possível. Por exemplo:

ProdutoEvent.as:

package
{
import flash.events.Event;
public class ProdutoEvent extends Event
{
public static const VIEW:String="view";
public static const DELETE:String="delete";
public static const UPDATE:String="update";
// etc... colocar aqui todos os tipos que quisermos aplicar à classe ProdutoEvent
public var produto:Produto;
public function ProdutoEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

Agora quando quisermos preparar um ProdutoEvent, deixamos de fazer:

var ev:ProdutoEvent=new ProdutoEvent('produtoClick');

e passamos a fazer:

var ev:ProdutoEvent=new ProdutoEvent(ProdutoEvent.VIEW);

Para escutarmos o evento, deixamos de fazer:

l.addEventListener('produtoClick', listagemProdutoClickHandler);

e passamos a fazer:

l.addEventListener(ProdutoEvent.VIEW, listagemProdutoClickHandler);

Criei um exemplo completo que demonstra a aplicação prática da explicação acima. Se a minha explicação não tiver sido suficiente, espero que o exemplo ajude a perceber a criação e utilização de Custom Events.

3 Comments

Make A Comment

Comments RSS Feed   TrackBack URL

Leave a comment

top