Explicar el manejo de eventos ExtJS 4


Recientemente he empezado a aprender ExtJS, y tengo problemas para entender cómo manejar los eventos. No tengo experiencia de ninguna versión anterior de ExtJS.

Al leer varios manuales, guías y páginas de documentación, he descubierto cómo usarlo, pero no tengo claro cómo funciona. He encontrado varios tutoriales para versiones anteriores de ExtJS, pero no estoy seguro de cuán aplicables son en ExtJS 4.

Estoy específicamente mirando la "última palabra" sobre las cosas como

  • ¿qué argumentos pasa una función de manejo de eventos? ¿Hay un conjunto estándar de args que siempre se pasan?
  • ¿cómo definir eventos personalizados para componentes personalizados que escribimos? ¿cómo podemos disparar estos eventos personalizados?
  • ¿el valor devuelto (verdadero/falso) afecta la forma en que el evento burbujea? Si no, ¿cómo podemos controlar el burbujeo de eventos desde dentro o fuera del controlador de eventos?
  • ¿hay una forma estándar de registrar a los oyentes de eventos? (Me he encontrado con dos diferentes maneras hasta ahora, y no estoy seguro de por qué se utilizó cada método).

Por ejemplo, esta pregunta me lleva a creer que un controlador de eventos puede recibir bastantes argumentos. He visto otros tutoriales donde solo hay dos argumentos para el controlador. ¿Qué cambios?

Author: Community, 2011-08-31

5 answers

Comencemos describiendo el manejo de eventos de los elementos DOM.

DOM node event handling

En primer lugar, no querría trabajar directamente con el nodo DOM. En su lugar, es probable que desee utilizar Ext.Element interfaz. Con el propósito de asignar controladores de eventos, Element.addListener y Element.on (estos son equivalentes) fueron creados. Así, por ejemplo, si tenemos html:

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

Y queremos agregar click controlador de eventos.
Vamos a recuperar Element:

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

Ahora vamos a comprobar los documentos para click evento. Su manejador puede tener tres parámetros:

Haga clic en (Ext.EventObject e, HTMLElement t, Object eOpts)

Sabiendo todo esto, podemos asignar controlador:

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

Manejo de eventos de widgets

El manejo de eventos de widgets es bastante similar al manejo de eventos de nodos DOM.

En primer lugar, el manejo de eventos de widgets se realiza utilizando Ext.util.Observable mixin. Con el fin de manejar los eventos correctamente su widget debe containg Ext.util.Observable como un mixin. Todos los widgets incorporados (como Panel, Formulario, Árbol, Cuadrícula,...) tiene Ext.util.Observable como mixin por defecto.

Para los widgets hay dos formas de asignar controladores. El primero es usar en el método (o addListener). Por ejemplo, vamos a crear Button widget y asignarle click evento. En primer lugar, debe comprobar los documentos del evento para los argumentos del controlador:

Haga clic en (Ext.botón.Botón esto, Evento e, Objeto eOpts )

Ahora usemos 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 segunda forma es usar los oyentes del widget config:

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

Observe que Button widget es un tipo especial de widgets. Haga clic en evento se puede asignar a este widget mediante el uso de handler config:

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

Eventos personalizados disparando

En primer lugar, debe registrar un evento utilizando el método addEvents :

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

Usar el método addEvents es opcional. Como comentarios a este método decir que no hay necesidad de utilizar este método, pero proporciona lugar para la documentación de eventos.

Para disparar tu evento usa método fireEvent :

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

arg1, arg2, arg3, /* ... */ será pasado al controlador. Ahora podemos manejar su evento:

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

Vale la pena mencionar que el mejor lugar para insertar addEvents la llamada al método es el método initComponent del widget cuando está definiendo un nuevo 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 */ });

Prevenir el evento burbujeo

Para prevenir burbujeo puede return false o utilizar Ext.EventObject.preventDefault(). Con el fin de evitar el uso de la acción predeterminada del navegador Ext.EventObject.stopPropagation().

Por ejemplo, asignemos el controlador de eventos de clic a nuestro botón. Y si no se hizo clic en el botón izquierdo evitar la acción predeterminada del navegador:

myButton.on('click', function(btn, e){
  if (e.button !== 0)
    e.preventDefault();
});
 216
Author: Molecular Man,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-29 06:26:30

Disparando eventos de toda la aplicación

Cómo hacer que los controladores hablen entre sí ...

Además de la gran respuesta anterior, quiero mencionar los eventos de toda la aplicación que pueden ser muy útiles en una configuración MVC para permitir la comunicación entre controladores. (extjs4. 1)

Digamos que tenemos una estación controladora (ejemplos de Sencha MVC) con un cuadro de selección:

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]);
    },    
   ...
});

Cuando el cuadro de selección desencadena un evento de cambio, la función onStationSelect es disparar.

Dentro de esa función vemos: {[17]]}

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

Esto crea y dispara un evento de toda la aplicación que podemos escuchar desde cualquier otro controlador.

Por lo tanto, en otro controlador ahora podemos saber cuándo se ha cambiado la casilla de selección de la estación. Esto se hace escuchando this.application.on de la siguiente manera:

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 el selectbox ha sido cambiado ahora disparamos la función onStationStart en el controlador Song también ...

Desde el Sencha docs:

Los eventos de aplicación son extremadamente útiles para eventos que tienen muchos controladores. En lugar de escuchar el mismo evento de vista en cada uno de estos controladores, solo un controlador escucha el evento de vista y dispara un evento de toda la aplicación que los demás pueden escuchar. Esto también permite a los controladores comunicarse entre sí sin saber o dependiendo de la existencia del otro.

En mi caso: Hacer clic en un nodo de árbol para actualizar los datos en un panel de rejilla.

Actualización 2016 gracias a @ gm2008 de los comentarios a continuación:

En términos de disparar eventos personalizados para toda la aplicación, ahora hay un nuevo método después de que se publique ExtJS V5.1, que usa Ext.GlobalEvents.

Cuando dispares eventos, puedes llamar: Ext.GlobalEvents.fireEvent('custom_event');

Cuando registras un controlador del evento, llamas a: Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope);

Este método no se limita a los controladores. Cualquier componente puede manejar un evento personalizado a través de poner el objeto componente como ámbito del parámetro de entrada.

Encontrado en Sencha Docs: MVC Part 2

 42
Author: mahatmanich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-21 11:05:46

Un truco más para los oyentes de eventos del controlador.

Puedes usar comodines para ver un evento desde cualquier componente:

this.control({
   '*':{ 
       myCustomEvent: this.doSomething
   }
});
 13
Author: dbrin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-04 19:31:59

Solo quería añadir un par de peniques a las excelentes respuestas anteriores: Si está trabajando en pre Extjs 4.1, y no tiene eventos de toda la aplicación, pero los necesita, he estado utilizando una técnica muy simple que podría ayudar: Cree un objeto simple que extienda Observable y defina cualquier evento de aplicación que pueda necesitar en él. A continuación, puede disparar esos eventos desde cualquier lugar de su aplicación, incluido el elemento dom html real y escucharlos desde cualquier componente mediante la transmisión de los elementos necesarios desde ese componente.

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

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

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

Entonces puedes, desde cualquier otro componente:

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

Y dispararlos desde cualquier componente o elemento dom:

 MessageBus.fireEvent('event1', somearg);

 <input type="button onclick="MessageBus.fireEvent('event2', 'somearg')">
 12
Author: Harel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-02 19:44:02

Solo dos cosas más que encontré útiles para saber, incluso si no son parte de la pregunta, en realidad.

Puede usar el método relayEvents para decirle a un componente que escuche ciertos eventos de otro componente y luego dispararlos nuevamente como si se originaran en el primer componente. Los documentos de la API dan el ejemplo de una red que retransmite el evento store load. Es muy útil cuando se escriben componentes personalizados que encapsulan varios subcomponentes.

Al revés, es decir, pasando los eventos recibidos por un componente de encapsulación mycmp a uno de sus subcomponentes subcmp, se pueden hacer así

mycmp.on('show' function (mycmp, eOpts)
{
   mycmp.subcmp.fireEvent('show', mycmp.subcmp, eOpts);
});
 11
Author: blahgonaut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-12 09:21:11