Jquery Observer pattern

放肆的年华 提交于 2019-11-28 20:57:45

From your comment:

I just can't see how this is achieved when you have to tell the subject which elements to trigger by selectors instead of the subject having a list that the observer can register to

Please correct me if I'm wrong, but you seem to be misunderstanding how the pattern was implemented in jQuery. You don't "tell the subject which elements to trigger", and the subject doesn't have "a list that the observer can register to" either. It works like this:

  • The subject/publisher emits/triggers certain events (on certain circumstances you define).
  • The observer/subscriber listens to certain events. It keeps a list of the events it subscribed to.
  • That's all based on DOM events, so it's limited by the DOM Event Model.

For example, consider the following HTML:

<div id="div1">div 1</div>
<div id="div2">div 2</div>

Let's make the inner divs trigger a custom event called 'custom'. You define when that should happen, on this example this will happen when they are clicked:

$('div').on('click', function(e) {
    $(this).trigger('custom');
});

Now let's make the document element subscribe to that custom event:

$(document).on('custom', function(e) {
    console.log('document is handling custom event triggered by ' + e.target.id);
});

When the custom event is triggered by one of the divs, the observer/subscriber is notified and a message is logged to the console.

The example uses document as the observer for a reason: events bubble up the DOM tree, and can only be caught by elements that are ancestors of the one that triggered it. Since document is the root of the DOM tree, it can see all events. If #div1 was our observer, it would only see events triggered by #div1 itself, but not the ones triggered by #div2.

Maybe that limitation is what confused you?


There are ways to circumvent that limitation, but usually, if you want to do something to #div1 based upon an event triggered by #div2, you just do it from the callback you have setup on the document element (or the closest common ancestor to both divs). Anyway, it seems you really want an alternative, so here is one in the form of a jQuery plugin:

$.fn.observe = function(eventName, callback) {
    return this.each(function(){
        var el = this;
        $(document).on(eventName, function(){
            callback.apply(el, arguments);
        })
    });
}

You can use it like this:

$('#div1').observe('custom', function(e) {
    // do something
});

Live example: http://jsfiddle.net/JwJsP/1

Might be not what you are looking for, however observers can subscribe for listening events:

        $(document).on('customEvent', '.iObserver', function() {
            console.log('i am observer');
        });

        // add observer
        $('ul li#Observer').addClass('iObserver');

        //remove observer
        $('ul li#Observer').removeClass('iObserver');

If you're still looking for some implementation using the events engine of jQuery you can try this code:

//The implementation   
(function($) {

    var o = $({});

    $.each({
        trigger: 'publish',
        on: 'subscribe',
        off: 'unsubscribe'
    }, function(key, val) {
        jQuery[val] = function() {
            o[key].apply(o, arguments);
        };
    });

})(jQuery);


// The way to use it is this:
var somedata = [1, 2, 3, 5, 4, 7, 8];
$.publish('myEvent', somedata); // with data
$.publish('myEvent'); // without data

$.subscribe('myEvent', function(event, data) {
    // handle the event
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!