Adjuntar controladores ExtJS MVC a elementos DOM, no componentes
extjs4 extjs-mvc (5)
No, esto parece no ser posible. Ext.EventBus escucha los eventos activados por los componentes de ExtJS. Tus elementos DOM estándar no disparan esos eventos. Además, la consulta se comprueba con los componentes de ExtJS es el método (selector de cadenas), que los elementos DOM no pueden invocar. Alguien podría corregirme si me equivoco, pero estoy seguro de que no es posible, desafortunadamente.
¿Hay alguna forma de utilizar el método Ext.app.Controller control () pero pasar una consulta DOM? Tengo una página que contiene enlaces estándar y me gustaría agregarles un controlador de clics aunque no se hayan creado como botones Ext.
He intentado
Ext.define(''app.controller.TabController'', {
extend: ''Ext.app.Controller'',
init: function() {
console.log("init");
this.control({
''a'': {
click: this.changeTab
}
});
},
changeTab: function() {
alert("new tab!");
}
});
Pero al hacer clic en enlaces no se activa la alerta.
¿Hay alguna manera de especificar un selector de CSS con this.control? ¿O solo funciona con componentes?
He encontrado una solución alternativa para este problema. No es tan directo como uno podría esperar, pero deja todo su código de "acción" en el controlador.
requerimiento : Envuelva la sección html de su página en un Ext.Component
real. Este será probablemente el caso de cualquier manera. Entonces, por ejemplo, puede tener una vista simple que contenga su HTML de la siguiente manera:
Ext.define(''app.view.myView'', {
extend: ''Ext.panel.Panel'',
alias: ''widget.myView'',
title: ''My Cool Panel'',
html: ''<div><a href="#">This link will open a window</a></div><br /> <label for="myInput">Type here: </label><input name="myInput" type="text" value="" />'',
initComponent: function(){
var me = this;
me.callParent(arguments);
}
});
Luego, en el controlador, utiliza el evento afterrender
para aplicar oyentes a sus elementos DOM. En el siguiente ejemplo, ilustre tanto los enlaces (un elemento) como los elementos de entrada:
Ext.define(''app.controller.myController'', {
extend: ''Ext.app.Controller'',
init: function() {
this.control({
''myView'': {
afterrender: function(cmp){
var me = this; //the controller
var inputs = cmp.getEl().select(''input''); // will grab all DOM inputs
inputs.on(''keyup'', function(evt, el, o){
me.testFunction(el); //you can call a function here
});
var links = cmp.getEl().select(''a''); //will grab all DOM a elements (links)
links.on(''click'', function(evt, el, o){
//or you can write your code inline here
Ext.Msg.show({
title: ''OMG!'',
msg: ''The controller handled the "a" element! OMG!''
});
});
}
}
});
},
testFunction: function(el) {
var str = ''You typed '' + el.value;
Ext.Msg.show({
title: ''WOW!'',
msg: str
});
}
});
¡Y ahí lo tienes, elementos DOM manejados dentro del controlador y adheridos a la arquitectura MVC!
También tengo una solución que soluciona este problema. Utilizo esta técnica a pesar de todo, ya que tiene otros beneficios: creé un bus de mensajería amplio para toda la aplicación. Es un objeto en mi aplicación que amplía Observable y define algunos eventos. Luego puedo activar esos eventos desde cualquier lugar de mi aplicación, incluidos los enlaces html a. Cualquier componente que quiera escuchar esos eventos puede transmitirlos y se dispararán como si hubieran sido disparados desde ese componente.
Ext.define(''Lib.MessageBus'', {
extend: ''Ext.util.Observable'',
constructor: function() {
this.addEvents(
"event1",
"event2"
);
this.callParent(arguments);
}
});
Luego, cada uno de los demás puede agregar esto después de la inicialización:
this.relayEvents(''Lib.MessageBus'', [''event1'',''event2'']);
y luego escucha esos eventos. Puedes disparar los eventos desde cualquier cosa haciendo:
Lib.MessageBus.fireEvent(''event1'', ''param a'', ''param b'')
y puedes hacerlo desde cualquier cosa, incluidos los enlaces html.
Muy útil para disparar eventos de una parte de la aplicación a otra.
Hice esta pregunta en SenchaCon este año, los desarrolladores de Sencha declararon que su intención es que los oyentes de DOM se deben adjuntar a su vista, y la vista debe resumirlos en eventos de componentes más significativos y refinarlos.
Por ejemplo, supongamos que está creando una vista llamada UserGallery que muestra una cuadrícula de caras de personas. Dentro de su clase de vista UserGallery, debería escuchar el evento DOM click en la etiqueta <img>
para recibir evento y destino, y luego la vista podría disparar un evento componente llamado "userselected" y pasar la instancia modelo para el usuario cliqueado en lugar de el objetivo DOM.
El objetivo final es que solo sus puntos de vista estén relacionados con elementos como los eventos de interfaz y los elementos DOM mientras que el controlador de nivel de aplicación solo trata con intenciones significativas del usuario. Su aplicación y el código del controlador no deben estar acoplados a su estructura de marcado o implementación de interfaz.
Vista de muestra
Ext.define(''MyApp.view.UserGallery'', {
extend: ''Ext.Component''
,xtype: ''usergallery''
,tpl: ''<tpl for="users"><img src="{avatar_src}" data-ID="{id}"></tpl>''
,initComponent: function() {
this.addEvents(''userselected'');
this.callParent(arguments);
}
,afterRender: function() {
this.mon(this.el, ''click'', this.onUserClick, this, {delegate: ''img''});
this.callParent(arguments);
}
,onUserClick: function(ev, t) {
ev.stopEvent();
var userId = Ext.fly(t).getAttribute(''data-ID'');
this.fireEvent(''userselected'', this, userId, ev);
}
});
Notas sobre las vistas
- Extienda "Ext.Component" cuando todo lo que desea es un
<div>
administrado, Ext.Panel es mucho más pesado para admitir elementos como barras de título, barras de herramientas, contraer, etc. - Use escuchas "administradas" cuando adjunte oyentes a elementos DOM de un componente (consulte Component.mon). Los oyentes gestionados por componentes se liberarán automáticamente cuando se destruya ese componente
- Al escuchar el mismo evento desde múltiples elementos DOM, utilice la opción de evento "delegar" y adjunte el oyente a su elemento primario común en lugar de a los elementos individuales. Esto funciona mejor y le permite crear / destruir elementos secundarios de forma arbitraria sin preocuparse por adjuntar / eliminar continuamente detectores de eventos para cada niño. Evite usar algo como
.select(''img'').on(''click'', handler)
- Al disparar un evento desde una vista, la convención de Sencha es que el primer parámetro para el evento sea el
scope
: una referencia a la vista que activó el evento. Esto es conveniente cuando el evento se maneja desde un controlador donde necesitará el alcance real del controlador de eventos para ser el controlador.
Controlador de muestra
Ext.define(''app.controller.myController'', {
extend: ''Ext.app.Controller''
,init: function() {
this.control({
''usergallery'': {
userselected: function(galleryView, userId, ev) {
this.openUserProfile(userID);
}
}
});
}
,openUserProfile: function(userId) {
alert(''load another view here'');
}
});
Recientemente tuve el mismo problema (mezclando mvc con algunos componentes no). Solo pensé en incluir esto como una respuesta, ya que parece bastante simple y funciona para mí :)
Ext.define(''app.controller.TabController'', {
extend: ''Ext.app.Controller'',
init: function() {
console.log("init");
this.control({
/* ''a'': {
click: this.changeTab
} */
});
var link = Ext.dom.Query.selectNode(''a'');
Ext.get(link).on(''click'', this.changeTab);
},
changeTab: function() {
alert("new tab!");
}
});