Expliquer la gestion des événements ExtJS 4

130

J'ai récemment commencé à apprendre ExtJS et j'ai du mal à comprendre comment gérer les événements. Je n'ai aucune expérience des versions précédentes d'ExtJS.

En lisant divers manuels, guides et pages de documentation, j'ai compris comment l'utiliser, mais je ne sais pas comment cela fonctionne. J'ai trouvé plusieurs tutoriels pour les anciennes versions d'ExtJS, mais je ne suis pas sûr de leur applicabilité dans ExtJS 4.

Je cherche spécifiquement le "dernier mot" sur des choses comme

  • quels arguments une fonction de gestion d'événements est-elle passée? Existe-t-il un ensemble standard d'arguments qui sont toujours passés?
  • comment définir des événements personnalisés pour les composants personnalisés que nous écrivons? comment pouvons-nous déclencher ces événements personnalisés?
  • la valeur de retour (vrai / faux) affecte-t-elle la façon dont l'événement bouillonne? Si ce n'est pas le cas, comment pouvons-nous contrôler le bouillonnement d'événements depuis l'intérieur ou l'extérieur du gestionnaire d'événements?
  • existe-t-il un moyen standard d'enregistrer les écouteurs d'événements? (J'ai rencontré deux façons différentes jusqu'à présent, et je ne sais pas pourquoi chaque méthode a été utilisée).

Par exemple, cette question me porte à croire qu'un gestionnaire d'événements peut recevoir pas mal d'arguments. J'ai vu d'autres tutoriels où il n'y a que deux arguments pour le gestionnaire. Quels changements?

jrharshath
la source
2
Juste remarqué ... hors sujet?
jrharshath
12
88 votes positifs sur la question, 155 votes positifs sur la première réponse et le grand et puissant Andrew décide que celle-ci est hors sujet. Grave coup de courant en cours!
boatcoder
3
J'ai voté pour rouvrir cette question car les réponses ici sont une mine d'or. J'ai modifié la question pour qu'elle corresponde mieux au style Q et A.
dbrin
1
Veuillez ouvrir à nouveau cette question car c'est une question vraiment utile et authentique. si aveuglément nous ne pouvons pas le fermer.
Piyush Dholariya
2
C'est une question bien formulée et je ne vois aucune raison de la clore. Appeler cela hors sujet est ridicule. Voté pour la réouverture.
Mike Fuchs le

Réponses:

222

Commençons par décrire la gestion des événements des éléments DOM.

Gestion des événements du nœud DOM

Tout d'abord, vous ne voudriez pas travailler directement avec le nœud DOM. Au lieu de cela, vous voudrez probablement utiliser l' Ext.Elementinterface. Dans le but d'affecter des gestionnaires d'événements, Element.addListeneret Element.on(ceux-ci sont équivalents) ont été créés. Donc, par exemple, si nous avons html:

<div id="test_node"></div>

et nous voulons ajouter clickun gestionnaire d'événements.
Récupérons Element:

var el = Ext.get('test_node');

Maintenant, vérifions les documents pour l' clickévénement. Son gestionnaire peut avoir trois paramètres:

cliquez sur (Ext.EventObject e, HTMLElement t, Object eOpts)

Connaissant tout cela, nous pouvons attribuer un gestionnaire:

//       event name      event handler
el.on(    'click'        , function(e, t, eOpts){
  // handling event here
});

Gestion des événements des widgets

La gestion des événements des widgets est assez similaire à la gestion des événements des nœuds DOM.

Tout d'abord, la gestion des événements des widgets est réalisée en utilisant Ext.util.Observablemixin. Afin de gérer correctement les événements, votre widget doit contenir Ext.util.Observableun mixin. Tous les widgets intégrés (comme Panel, Form, Tree, Grid, ...) ont Ext.util.Observablecomme mixin par défaut.

Pour les widgets, il existe deux manières d'attribuer des gestionnaires. Le premier - est à utiliser sur la méthode (ou addListener). Créons par exemple un Buttonwidget et attribuons-lui un clickévénement. Tout d'abord, vous devez vérifier les documents de l'événement pour les arguments du gestionnaire:

cliquez sur (bouton ext.Bouton this, Event e, Object eOpts)

Utilisons maintenant on:

var myButton = Ext.create('Ext.button.Button', {
  text: 'Test button'
});
myButton.on('click', function(btn, e, eOpts) {
  // event handling here
  console.log(btn, e, eOpts);
});

La deuxième façon est d'utiliser la configuration des écouteurs du widget :

var myButton = Ext.create('Ext.button.Button', {
  text: 'Test button',
  listeners : {
    click: function(btn, e, eOpts) {
      // event handling here
      console.log(btn, e, eOpts);
    }
  }
});

Notez que le Buttonwidget est un type spécial de widgets. L'événement Click peut être attribué à ce widget en utilisant handlerconfig:

var myButton = Ext.create('Ext.button.Button', {
  text: 'Test button',
  handler : function(btn, e, eOpts) {
    // event handling here
    console.log(btn, e, eOpts);
  }
});

Tir d'événements personnalisés

Tout d'abord, vous devez enregistrer un événement à l'aide de la méthode addEvents :

myButton.addEvents('myspecialevent1', 'myspecialevent2', 'myspecialevent3', /* ... */);

L'utilisation de la addEventsméthode est facultative. Comme le disent les commentaires sur cette méthode, il n'est pas nécessaire d'utiliser cette méthode, mais elle fournit de la place pour la documentation des événements.

Pour déclencher votre événement, utilisez la méthode fireEvent :

myButton.fireEvent('myspecialevent1', arg1, arg2, arg3, /* ... */);

arg1, arg2, arg3, /* ... */sera passé au gestionnaire. Maintenant, nous pouvons gérer votre événement:

myButton.on('myspecialevent1', function(arg1, arg2, arg3, /* ... */) {
  // event handling here
  console.log(arg1, arg2, arg3, /* ... */);
});

Il convient de mentionner que le meilleur endroit pour insérer un appel de méthode addEvents est la initComponentméthode du widget lorsque vous définissez un nouveau widget:

Ext.define('MyCustomButton', {
  extend: 'Ext.button.Button',
  // ... other configs,
  initComponent: function(){
    this.addEvents('myspecialevent1', 'myspecialevent2', 'myspecialevent3', /* ... */);
    // ...
    this.callParent(arguments);
  }
});
var myButton = Ext.create('MyCustomButton', { /* configs */ });

Empêcher le bouillonnement d'événements

Pour éviter les bulles, vous pouvez return falseou utiliser Ext.EventObject.preventDefault(). Afin d'empêcher l'utilisation de l'action par défaut du navigateur Ext.EventObject.stopPropagation().

Par exemple, affectons le gestionnaire d'événements click à notre bouton. Et si vous n'avez pas cliqué sur le bouton gauche, empêchez l'action du navigateur par défaut:

myButton.on('click', function(btn, e){
  if (e.button !== 0)
    e.preventDefault();
});
Homme moléculaire
la source
3
c'est de la cupidité, mais y a-t-il un moyen de faire la chose "addEvents" via une configuration? :)
jrharshath
@jrharshath, pour autant que je sache, malheureusement, il n'y a aucun moyen de le faire via config.
Molecular Man
comment crée-t-on ces -'myspecialevent1 ', je vois que vous l'avez attaché et que vous l'avez manipulé, mais comment pouvons-nous les créer?
heyNow
1
Réponse géniale! Je suis nouveau sur ExtJs et je cherchais un moyen de référencer n'importe quel élément de la page et d'utiliser des gestionnaires d'événements sur eux, tout comme jQuery. Vous m'avez appris à! Merci!
Rutwick Gangurde
1
petite erreur dans la section "Empêcher le bouillonnement d'événements". stopPropagation est utilisé pour empêcher la publication d'événement, et preventDefault est utilisé pour empêcher le comportement / l'action par défaut.
MatRt
44

Déclencher des événements à l'échelle de l'application

Comment faire en sorte que les contrôleurs se parlent ...

En plus de la très bonne réponse ci-dessus, je veux mentionner les événements à l'échelle de l'application qui peuvent être très utiles dans une configuration MVC pour permettre la communication entre les contrôleurs. (extjs4.1)

Disons que nous avons une station de contrôle (exemples Sencha MVC) avec une boîte de sélection:

Ext.define('Pandora.controller.Station', {
    extend: 'Ext.app.Controller',
    ...

    init: function() {
        this.control({
            'stationslist': {
                selectionchange: this.onStationSelect
            },
            ...
        });
    },

    ...

    onStationSelect: function(selModel, selection) {
        this.application.fireEvent('stationstart', selection[0]);
    },    
   ...
});

Lorsque la boîte de sélection déclenche un événement de modification, la fonction onStationSelectest déclenchée.

Dans cette fonction, nous voyons:

this.application.fireEvent('stationstart', selection[0]);

Cela crée et déclenche un événement à l'échelle de l'application que nous pouvons écouter à partir de n'importe quel autre contrôleur.

Ainsi, dans un autre contrôleur, nous pouvons maintenant savoir quand la boîte de sélection de station a été modifiée. Cela se fait en écoutant this.application.oncomme suit:

Ext.define('Pandora.controller.Song', {
    extend: 'Ext.app.Controller', 
    ...
    init: function() {
        this.control({
            'recentlyplayedscroller': {
                selectionchange: this.onSongSelect
            }
        });

        // Listen for an application wide event
        this.application.on({
            stationstart: this.onStationStart, 
                scope: this
        });
    },
    ....
    onStationStart: function(station) {
        console.info('I called to inform you that the Station controller select box just has been changed');
        console.info('Now what do you want to do next?');
    },
}

Si la boîte de sélection a été modifiée, nous déclenchons maintenant la fonction onStationStartdans le contrôleur Songégalement ...

Extrait de la documentation Sencha:

Les événements d'application sont extrêmement utiles pour les événements qui ont de nombreux contrôleurs. Au lieu d'écouter le même événement de vue dans chacun de ces contrôleurs, un seul contrôleur écoute l'événement de vue et déclenche un événement à l'échelle de l'application que les autres peuvent écouter. Cela permet également aux contrôleurs de communiquer entre eux sans se connaître ou en fonction de leur existence.

Dans mon cas: Cliquer sur un nœud d'arbre pour mettre à jour les données dans un panneau de grille.

Mise à jour 2016 grâce à @ gm2008 des commentaires ci-dessous:

En termes de déclenchement d'événements personnalisés à l'échelle de l'application, il existe une nouvelle méthode après la publication d' ExtJS V5.1 , qui utilise Ext.GlobalEvents.

Lorsque vous déclenchez des événements, vous pouvez appeler: Ext.GlobalEvents.fireEvent('custom_event');

Lorsque vous enregistrez un gestionnaire de l'événement, vous appelez: Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope);

Cette méthode n'est pas limitée aux contrôleurs. Tout composant peut gérer un événement personnalisé en plaçant l'objet composant en tant que portée du paramètre d'entrée.

Trouvé dans Sencha Docs: MVC Part 2

mahatmanich
la source
1
En termes de déclenchement d'événements personnalisés à l'échelle de l'application, il existe une nouvelle méthode après la publication d'ExtJS V5.1, qui utilise Ext.GlobalEvents. Lorsque vous déclenchez un événement, vous appelez Ext.GlobalEvents.fireEvent('custom_event');Lorsque vous enregistrez un gestionnaire de l'événement, vous appelez Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope};Here is a fiddle . Cette méthode n'est pas limitée aux contrôleurs. Tout composant peut gérer un événement personnalisé en plaçant l'objet composant en tant que paramètre d'entrée scope. La question devrait être rouverte.
gm2008
15

Une astuce de plus pour les écouteurs d'événements du contrôleur.

Vous pouvez utiliser des caractères génériques pour surveiller un événement à partir de n'importe quel composant:

this.control({
   '*':{ 
       myCustomEvent: this.doSomething
   }
});
dbrin
la source
12

Je voulais juste ajouter quelques pence aux excellentes réponses ci-dessus: Si vous travaillez sur des versions antérieures à Extjs 4.1 et que vous n'avez pas d'événements à l'échelle de l'application mais que vous en avez besoin, j'ai utilisé une technique très simple qui pourrait vous aider: Créez un objet simple étendant Observable et définissez tous les événements à l'échelle de l'application dont vous pourriez avoir besoin. Vous pouvez ensuite déclencher ces événements de n'importe où dans votre application, y compris l'élément dom html réel et les écouter à partir de n'importe quel composant en relayant les éléments requis à partir de ce composant.

Ext.define('Lib.MessageBus', {
    extend: 'Ext.util.Observable',

    constructor: function() {
        this.addEvents(
            /*
             * describe the event
             */
                  "eventname"

            );
        this.callParent(arguments);
    }
});

Ensuite, vous pouvez, à partir de n'importe quel autre composant:

 this.relayEvents(MesageBus, ['event1', 'event2'])

Et lancez-les depuis n'importe quel composant ou élément dom:

 MessageBus.fireEvent('event1', somearg);

 <input type="button onclick="MessageBus.fireEvent('event2', 'somearg')">
Harel
la source
Juste pour information, this.addEvents est obsolète à partir de EXT JS 5.0. Il n'est donc pas nécessaire d'ajouter des événements maintenant
Ajay Sharma
11

Encore deux choses que j'ai trouvées utiles à savoir, même si elles ne font pas partie de la question, vraiment.

Vous pouvez utiliser la relayEventsméthode pour demander à un composant d'écouter certains événements d'un autre composant, puis de les déclencher à nouveau comme s'ils provenaient du premier composant. La documentation de l'API donne l'exemple d'une grille relayant l' loadévénement store . C'est très pratique lors de l'écriture de composants personnalisés qui encapsulent plusieurs sous-composants.

L'inverse, c'est-à-dire transmettre les événements reçus par un composant d'encapsulation mycmpà l'un de ses sous-composants subcmp, peut être fait comme ceci

mycmp.on('show' function (mycmp, eOpts)
{
   mycmp.subcmp.fireEvent('show', mycmp.subcmp, eOpts);
});
blahgonaut
la source