Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

24mar/099

Flex Item Renderer – Communiquer avec un itemRenderer grâce à des Event

Toujours la suite de l'article de Peter Ent sur la communication entre les itemRenderer et votre application. Cette fois-ci, une nouvelle approche, plus modulaire qui est la manipulation d'évènements. Dans les exemples précédents, on a utilisé une TileList qui présente des produits. Chaque produit étant représenté par un itemRenderer avec une image, du texte et un bouton. Ce bouton sert en théorie à acheter le livre en question. Seulement, le <mx:Button> est dans l'itemRenderer et la phase d'achat se fera vraisemblablement dans votre application principale (pas dans l'itemRenderer en tout cas). Il faut donc faire remonter (bubble up) l'évènement du clic bouton vers l'application.

Quand l'utilisateur clique  sur un bouton pour acheter un livre, c'est le composant liste qui est responsable de communiquer cette information à l'application. Ce qui nous donne donc quelque chose comme:

<CatalogList buyBook="addToCart(event)" />

Voici donc le code à utiliser pour dispatcher cet évènement de manière propre par le composant Liste. Tous les composants (CatalogList) sont issus de l'exemple précédent.

  • Ajouter tout d'abord un tag metadata au composant CatalogList pour indiquer au compilateur que le composant va dispatcher l'évènement
import events.BuyBookEvent;
import mx.controls.TileList;

[Event(name="buyBook",type="events.BuyBookEvent")]

public class CatalogList extends TileList{
...
  • Ajouter une fonction à CatalogList pour propage l'évènement. Cette fonction sera appelée par les instances d'itemRenderer:
public function dispatchBuyEvent( item:Object ) : void{
	var event:BuyBookEvent = new BuyBookEvent();
	event.bookData = item;
	dispatchEvent( event );
}
  • Changer le code du bouton Buy de l'itemRenderer pour qu'il invoke cette fonction :
<mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]">
    <mx:click>
    <![CDATA[
        (listData.owner as CatalogList).dispatchBuyEvent(data);
    ]]>
    </mx:click>
</mx:Button>

Maintenant, le Button de l'itemRenderer peut simplement invoquer une fonction du composant liste avec la donnée de l'enregistrement lui correspondant. Cela passe la responsabilité de la réaction à cette action sur le composant List.

Flex ActionScript - Passer des paramètres avec un Event personnalisé

Le composant liste dans cet exemple dispatch un event avec de la data. L'application peut ajouter des event listeners en utilisant de l'ActionScript (grâce au tag [Event] dans CatalogList.as) ou en MXML. Le tag [Event] rend la tâche plus facile aux développeurs.

Petit exemple en pratique (avec les sources):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" creationComplete="cHandler(event)" viewSourceURL="srcview/index.html">
	<mx:XML id="XMLData" source="data.xml"/>

	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import events.BuyBookEvent;

			private function cHandler(event:Event):void{
				mylist.addEventListener(BuyBookEvent.BUY_BOOK, alertData);
			}

			private function alertData(event:BuyBookEvent):void{
				Alert.show("Prix: " + event.bookData.price + "€");
			}
		]]>
	</mx:Script>

	<local:CatalogList id="mylist"  width="560" itemRenderer="BookItemRenderer"
       dataProvider="{XMLData.book}" height="350" columnWidth="275" rowHeight="135" buyBook="{alertData(event)}"/>

</mx:Application>

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

Petite conclusion sur la communication ItemRenderer / Application

  • Les itemRenderer doivent communiquer des actions en utilisant des évènements (Event). Les évènements personnalisés permettent de passer de la data avec l'évènement  pour que l'entité qui capte l'évènement ne doive pas aller chercher la data dans l'itemRenderer.
  • Les itemRenderer doivent réagir aux changements de la data en faisant des override sur les fonctions set data(). On peut accéder aux valeurs depuis l'intérieur de ces fonction en utilisant listData.owner. Vous pouvez aussi accéder aux data stockées dans des variables static ou dans l'application principale par Application.application.

Articles similaires

Commentaires (9) Trackbacks (0)
  1. Hello,

    ton exemple me fait un peu penser à ce que je suis en train de faire actuellement... En gros, on pourrait imaginer en reprenant ton exemple que j'ai 2 catalogList une à coté de l'autre. Une qui représente les livres dispos, l'autre, mes livres favoris. Bien entendu, on retrouvera des doublons de livres.

    Plus complexe encore, mon dataProvider ressemble à quelque chose genre

    Actionscript:
    1. [Bindable] private var dataPr:Object = {
    2.    liste: [
    3.       { categorie: 'cat1', items: [ 'item1', 'item2', ... ] },
    4.       { categorie: 'cat2', items: [ 'cat2_item1', 'cat2_item2', ... ] },
    5.       { categorie: 'cat3', items: [ 'cat3_item1', 'cat3_item2', ... ] },
    6.    ],
    7.    favoris: [
    8.       'item1', 'cat2_item1'
    9.    ]
    10. };

    Donc, en gros, j'ai une "liste de liste".

    Dans mon itemRenderer, j'ai un bouton supplémentaire qui me permet disons de changer le prix du livre. Comment réussir à mettre à jour l'itemRenderer de mes "favoris" quand je change le prix dans le catalogList des livres dispos ?

    J'ai bien essayé en utilisant le dispatchEvent(new Event('foo', true)) et la, j'arrive bien à remonter la modification... par contre, pour la "redescendre" dans l'autre liste, la, je suis coincé.

  2. Salut,
    problème intéressant. Comme il est précisé, il ne faut pas essayer d'accéder à l'itemRenderer mais plutôt modifier la data qu'il a à afficher. Si tu arrives à faire remonter ta modification, c'est déjà un premier pas. il faut ensuite que tu modifies la data de ton dataProvider favoris. Pour cela, il faut que tu boucles sur ton dataProvider favoris pour trouver l'élément qui correspond à l'élémént que tu as modifié dans la liste de base. Une fois que tu as trouvé cet élément, tu pourra changer son prix directement et l'itemRenderer se mettra à jour.
    Par contre, essaie d'utiliser un ArrayCollection au lieu d'un Object, tu aura moins de mal pour les parcours et pour tes tests ;)

    Fabien

  3. La solution proposée ici oblige à surcharger la TileList, ou une DataGrid le cas échéant.
    Pour éviter celà, j'ai trouvé un site proposant une solution plus simple, utilisant le concept de bubble :
    "How to dispatch an event from a custom item renderer" http://nwebb.co.uk/blog/?p=16

    Il suffit d'abonner la TileList ou DataGrid ou autre à l'événement BuyBookEvent.
    Dans le renderer, à la création de l'event, mettre le paramètre bubble à true, ainsi l'événement sera automatiquement propagé à la TileList (ou DataGrid ou autre).
    Dans mon cas, ca fonctionne avec un AdvancedDatagrid

  4. Salut kanai,
    effectivement, le bubbling permet de ne pas faire d'héritage (au passage, tu perd les metadatas associées à ta list qui précisent le type d'évent dispatché). Par contre, n'oublies pas de bien stopper la propagation de l'évènement quand tu l'a récupéré car sinon celui-ci va remonter toute la liste d'affichage. Et à chaque fois qu'il remonte la liste d'affichage, la méthode Event::clone() est appélée qui crée une nouvelle instance de l'event, ce qui peut ralentir ton application

    Fabien

  5. Serait-il possible d'expliquer un peu le rôle de "criteria", j'ai beau chercher je ne comprend pas bien à quoi il sert. Merci

  6. Salut Rio Grande,
    je suppose que tu parles du "criteria" précisé dans un autre tutorial sur les IR, non ? Cette variable sert à définir le pallier à partir duquel il faut (ou pas) afficher les éléments

    Fabien

  7. Je parlais bien de cet exemple, en tout cas dans ce qui est présent dans les sources. D'ailleurs pas tous les fichiers sont visibles (quand on click sur "ItemRendererCommunicationB" par exemple).

    Mais j'ai utilisé la solution proposée par "kanai" que j'ai pu transposer à mon cas (en ajoutant un event.stopPropagation(); après récupération de l'événement). Je suis nouveau dans le domaine et j'ai eu du mal à comprendre pourquoi il faut que BookItemRenderer implemente IDropInListItemRenderer...

    (PS: ça serait cool de corriger le bug qui fait qu'on ne voit pas le champ d'édition des commentaires en blanc sous IE)

  8. Il y a un problème avec le lien des sources à la fin de l'article

  9. Salut,
    Cet article est un peu ancien, mieux vaut télécharger le ZIP avec les sources:
    http://www.flex-tutorial.fr/wp-content/uploads/ItemRendererCommunicationB/srcview/ItemRendererCommunicationB.zip

    Fabien


Leave a comment

(required)

Aucun trackbacks pour l'instant