itemView запускает пользовательское событие, достигающее родителя

У меня есть этот код http://jsfiddle.net/QRcF5/2/

$(function() {
    var Header = Backbone.Marionette.ItemView.extend({
        template: _.template('<h4>TEST</h4><button>EDIT</button>'),

        tagName: 'nav',

        triggers: {
            'click button': 'btn_clicked'
        }
    }),
    Layout = Backbone.Marionette.Layout.extend({
        template: _.template('<header></header>'),

        regions: {
            header: 'header'
        },

        events: {
            'itemview:btn_clicked': 'clicked'
        },

        clicked: function() {
            alert('Ana are mere');
        }
    });

    layout = new Layout();
    $('body').append(layout.render().el);
    layout.header.show(new Header());
});

Я использую макет с одним ItemView (позже я хочу более сложную вложенность) и хочу зафиксировать в LAYOUT событие, которое происходит в ITEMVIEW. Кажется, что он не пузырится вверх или я делаю что-то не так.


ОБНОВЛЕНИЕ 1. Я пробовал события, триггеры (для дочернего элемента) и события (для родителя), но я все еще не могу поймать событие внутри родителя.

Я могу использовать:

_.extend(App.vent, Backbone.Events);

Backbone.Marionette.ItemView.extend({
    ....
    App.vent.trigger('btn_clicked');
    ....
});

Backbone.Marionette.Layout.extend({
    ....
    App.vent.on('btn_clicked', function() { doCoding(); });
    ....
});

Но таким образом я нарушаю инкапсуляцию. Есть ли способ сохранить инкапсуляцию с помощью событий триггеров Marionette и сохранить все это в макете, а не загрязнять все приложение?


ОБНОВЛЕНИЕ 2

http://jsfiddle.net/QRcF5/5/

Я обновил jsfiddle, чтобы использовать _.extend(vent, Backbone.Events). Если у кого-то есть лучший шаблон для этого, сообщите нам: D


person Claudiu    schedule 19.08.2013    source источник


Ответы (3)


Я нашел решение (похоронен где-то в документации, делая некоторые связи между макетом, регионом и видом)!

http://jsfiddle.net/QRcF5/6/


В контексте связи ТОЛЬКО между родительским (макетом) и дочерним (itemView):

1) дочерний элемент запускает настраиваемое событие (в отличие от расширения Backbone.Events — оно обращается только к тем, у кого есть к нему доступ = инкапсуляция)

triggers: {
    'click button': 'custom_event:btn_clicked'
}


2) родитель прослушивает это событие, имея доступ к дочернему элементу с on('show',....) >

initialize: function() {
    var that = this; // needed for the listenTo which overrides 'THIS'

    this.header.on('show', function(view) {
        this.listenTo(view, 'custom_event:btn_clicked', that.clicked);
    });
},


Пример:

layout = new Layout();
$('body').append(layout.render().el);
layout.header.show(new Header()); // Here we get access to child and its events


(скрытая) сила Марионетки. (Я имею в виду, когда я говорю скрыто, потому что, поскольку документация относительно новая, документация примитивна, а сложных примеров мало).

При небольшом упорстве можно добиться чего угодно.

person Claudiu    schedule 27.08.2013

вы должны просто вернуть true и позволить клику появиться в DOM, см. http://jsfiddle.net/aGaDY/ :

var Header = Backbone.Marionette.ItemView.extend({
  template: _.template('<h4>TEST</h4><button>EDIT</button>'),
  events: {
    'click button': 'btn'
  },
  btn: function () {
    return true;
  }
}),

Layout = Backbone.Marionette.Layout.extend({
    template: _.template('<div>Before:</div><header></header><div>After:</div><div class="body">Body Goes Here</div>'),
    regions: {
        header: 'header'
    },
    events: {
        'click': 'btn_clicked'
    },
    btn_clicked: function () {
        alert('Ana are mere');
    }
});
layout = new Layout();
$('body').append(layout.render().el);
layout.header.show(new Header());

Вы даже можете полностью удалить обработку событий в ItemView, пузыри - это поведение по умолчанию.

ИЗМЕНИТЬ:

Если вы хотите иметь возможность различать нажатия разных кнопок и предотвращать загрязнение глобального пространства внутренними событиями, которые не касаются приложения, я могу подумать о двух вариантах.

Переместите данные в цель события с помощью функции данных jquery и event.target:

// In Header
bth:function(e){
  $(e.target).data("source", "myButton")
}
// ....
// in the Layout 
btn_click: function(e){
  if ($(e.target).data("source") === "myButton") this.doSomething()
}

Другой вариант заключается в том, что макет будет передавать в заголовок локальный расширенный объект backbone.Event, поэтому связь между ними будет частной.

Я понимаю вопрос инкапсуляции, но я думаю, что читабельность будет лучше в глобальном App.Vent, который вы предложили

person ekeren    schedule 20.08.2013
comment
@Symba Вы можете поместить логин в функцию Header btn, важно только, чтобы вы вернули true, чтобы включить всплытие. Я не понимаю, зачем нужен this.on('click'...? что не работает в jsfiddle? - person ekeren; 21.08.2013
comment
извините за мою ошибку в последнем комментарии. - person Claudiu; 21.08.2013
comment
Я неправильно понял себя. Я хочу инициировать пользовательское событие, потому что простой щелчок просто не сработает (слишком общий, у меня есть много других щелчков, кнопок и т. зависимость от структуры html (что крайне нежелательно). PS: в магистрали вам не нужно возвращать true, как вы сказали, пузыри - это поведение по умолчанию. - person Claudiu; 21.08.2013
comment
@Symba Добавлен раздел «Правка», может быть, это поможет. - person ekeren; 21.08.2013
comment
Как вы предложили, и как я думал, вентиляция все же менее плоха. Но, по крайней мере, я буду использовать тот, что внутри модуля, и не загрязнять глобальный App.Vent. Спасибо за ваше время: D - person Claudiu; 21.08.2013

events: {
            'itemview:btn': 'btn_clicked'
        },

Элемент просмотра - это не то, на что нажимают. Вам нужно указать фактический элемент dom следующим образом:

events: {
            'click .someThingWithAClass': 'myFunction'
        },

Однако, если вы хотите прослушивать события, которые происходят дальше по дорожке, вам, вероятно, следует просто придерживаться метода jquery on. Это будет слушать все, что всплывает, независимо от пользовательского интерфейса, который был сгенерирован во время рендеринга этого представления.

http://api.jquery.com/on/

person Scott    schedule 19.08.2013
comment
Я использую представление элементов следующим образом: >github.com/marionettejs/backbone.marionette/blob/master/docs/ Возможно, я ошибаюсь. - person Claudiu; 19.08.2013
comment
Что вы будете делать, так это прослушивать события, происходящие в объекте itemview, который существует в коде JS. События, происходящие в DOM, отличаются от событий, происходящих в javascript. Если вы слушаете клики, происходящие в DOM, то вам следует делать это с помощью нижнего фрагмента кода, который я написал. Если вы слушаете события, которые происходят на объекте просмотра марионетки, вам следует использовать свой способ (мой лучший) - person Scott; 20.08.2013
comment
Я ищу связь между представлением элементов и макетом в Marionette (например, у нас есть внутренняя связь между моделью и представлением в Backbone) - person Claudiu; 20.08.2013
comment
что это за ссылка? это официальный github марионетки github.com/marionettejs /backbone.marionette (у вас должна быть старая версия документов на github) - person Claudiu; 21.08.2013