Подключите контроллеры ExtJS MVC к элементам DOM, а не к компонентам - PullRequest
19 голосов
/ 18 мая 2011

Есть ли способ использовать метод control () Ext.app.Controller, но передать запрос DOM?У меня есть страница со стандартными ссылками, и я хотел бы добавить к ним обработчик кликов, даже если они не были созданы как кнопки Ext.ссылки не запускают оповещение.

Есть ли способ указать селектор CSS с помощью this.control?Или он работает только с компонентами?

Ответы [ 5 ]

39 голосов
/ 05 января 2012

Я задал этот вопрос на SenchaCon в этом году, разработчики Sencha заявили, что их намерение состоит в том, чтобы прослушиватели DOM были подключены к вашему представлению, а представление должно абстрагировать их в более значимые события компонентов и переопределить их.

Например, предположим, что вы создаете представление под названием UserGallery, которое показывает сетку лиц людей.В вашем классе представления UserGallery вы будете прослушивать событие нажатия DOM на теге <img>, чтобы получить событие и цель, а затем представление может запустить событие компонента с именем «userselected» и передать экземпляр модели для пользователя, которого щелкнули, вместоцель DOM.

Конечной целью является то, что только ваши представления должны быть связаны с такими вещами, как события интерфейса и элементы DOM, в то время как контроллер уровня приложения имеет дело только с осмысленными намерениями пользователя.Код вашего приложения и контроллера вообще не должен быть связан с вашей структурой разметки или реализацией интерфейса.

Пример представления

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);
    }
});

Примечания к представлениям

  • Расширить«Ext.Component», когда все, что вам нужно, это управляемый <div>, Ext.Panel намного тяжелее для поддержки таких вещей, как заголовки, панели инструментов, свертывание и т. Д.
  • Используйте «управляемых» слушателей при подключении слушателейЭлементы DOM из компонента (см. Component.mon).Прослушиватели, управляемые компонентами, будут автоматически освобождены, когда этот компонент будет уничтожен
  • При прослушивании одного и того же события из нескольких элементов DOM используйте опцию события «делегат» и присоедините слушателя к их общему родителю, а не к отдельному.элементы.Это работает лучше и позволяет вам создавать / уничтожать дочерние элементы произвольно, не беспокоясь о постоянном присоединении / удалении слушателей событий к каждому дочернему элементу.Старайтесь не использовать что-то вроде .select('img').on('click', handler)
  • При запуске события из представления, соглашение Сенчи гласит, что первым параметром события будет scope - ссылка на представление, которое вызвало событие.Это удобно, когда событие обрабатывается из контроллера, где вам нужен фактический объем обработчика событий, чтобы быть контроллером.

Sample Controller

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');
    }
});
3 голосов
/ 24 сентября 2011

Я нашел решение этой проблемы.Он не такой прямой, как можно надеяться, но он оставляет весь ваш код «действия» в контроллере.

требование : оберните html-раздел вашей страницы в фактический Ext.Component.Скорее всего, так и будет.Например, у вас может быть простое представление, содержащее ваш HTML-код:

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);
    }
});

Затем в контроллере вы используете событие afterrender для применения слушателей к вашим элементам DOM.В приведенном ниже примере я иллюстрирую обе ссылки (элемент) и элементы ввода:

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
        });
    }   
});

И вот, у вас это есть, элементы DOM обрабатываются внутри контроллера и придерживаются архитектуры MVC!

1 голос
/ 20 мая 2011

Нет, это кажется невозможным.Ext.EventBus прослушивает события, запускаемые компонентами ExtJS.Ваши стандартные элементы DOM не запускают эти события.Кроме того, запрос проверяется с помощью метода ExtJS componets (String selector), который не может вызываться элементами DOM.Кто-то может исправить меня, если я ошибаюсь, но я уверен, что это невозможно, к сожалению.

0 голосов
/ 21 августа 2013

У меня недавно была такая же проблема (смешивание mvc с некоторыми некомпонентными компонентами). Просто подумал, что я добавлю это в качестве ответа, поскольку это кажется довольно простым и работает для меня:)

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!");
    }   
});
0 голосов
/ 18 марта 2013

У меня также есть решение, которое работает вокруг этой проблемы. Я использую эту технику, несмотря на то, что она имеет и другие преимущества: я создал шину обмена сообщениями для приложений. Это объект в моем приложении, который расширяет Observable и определяет несколько событий. Затем я могу вызвать эти события из любого приложения в моем приложении, включая html a ссылки. Любой компонент, который хочет прослушать эти события, может ретранслировать их, и они будут запускаться, как если бы они запускались из этого компонента.

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

    constructor: function() {
        this.addEvents( 
                  "event1",
                  "event2"
                 );
        this.callParent(arguments);
    }
});

Затем каждый компонент может добавить это после инициализации:

this.relayEvents('Lib.MessageBus', ['event1','event2']);

и затем слушайте эти события. Вы можете вызвать события из чего угодно, выполнив:

Lib.MessageBus.fireEvent('event1', 'param a', 'param b')

и вы можете сделать это из любого, включая html-ссылки.

Очень удобно запускать события из одной части приложения в другую.

...