Подтвердить что ты не робот

Присоедините контроллеры ExtJS MVC к элементам DOM, а не к компонентам

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

Я пробовал

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

Но при нажатии на ссылки не срабатывает предупреждение.

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

4b9b3361

Ответ 1

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

Например, предположим, что вы создаете представление UserGallery, которое отображает сетку лиц. В вашем классе UserGallery вы будете прослушивать событие DOM click в теге <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)
  • При запуске события из представления соглашение Sencha заключается в том, что первым параметром события будет scope - ссылка на представление, которое произвело событие. Это удобно, когда событие обрабатывается с контроллера, где вам понадобится фактическая область действия обработчика события как контроллера.

Контроллер образца

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

Ответ 2

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

requirment: оберните раздел 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!

Ответ 3

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

Ответ 4

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

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

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

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

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

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

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

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

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

Ответ 5

У меня была такая же проблема в последнее время (смешение 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!");
    }   
});