最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript Module Pattern Events and Listeners - Stack Overflow

programmeradmin0浏览0评论

I'm implementing the module pattern, and would like to know the best/preferred way to define and register event listeners/handlers. The following works, but maybe there is a better/simpler way...

var  MODULE = function() {

    //  private
    var _field1;
    var _field2;

    function  localFunc(p) {
        alert('localFunc');
    }

    //  public
    return {
        // properties
        prop1: _field1,

        // events
        myEvent1Handler: {},
        myEvent1: function() {myEvent1Handler();},
        myEvent2Handler: {},
        myEvent2: function() {myEvent2Handler();},

        addListener: function  (event,func) {
            if (event  ==  "myEvent1")
                myEvent1Handler = func;   

            if (event  ==  "myEvent2")
                myEvent2Handler = func;      
        },

        // public  methods
        method1: function (p) {
            alert('method1 says:' + p);
            MODULE.myEvent1();
        },
        method2: function  (p) {
             alert('method2 doing  stuff');
             localFunc(p);
            MODULE.myEvent2();
        }

    };
}();

// register for events
MODULE.addListener("myEvent1",function(){alert('fired1');});  
MODULE.addListener("myEvent2",function(){alert('fired2');});  

// use module (only event1 should fire!)
MODULE.method1("hello");  

Try it out:

/

Seems like a lot of work to have myEventx, myEventHandlerx, and addListener?

I'm implementing the module pattern, and would like to know the best/preferred way to define and register event listeners/handlers. The following works, but maybe there is a better/simpler way...

var  MODULE = function() {

    //  private
    var _field1;
    var _field2;

    function  localFunc(p) {
        alert('localFunc');
    }

    //  public
    return {
        // properties
        prop1: _field1,

        // events
        myEvent1Handler: {},
        myEvent1: function() {myEvent1Handler();},
        myEvent2Handler: {},
        myEvent2: function() {myEvent2Handler();},

        addListener: function  (event,func) {
            if (event  ==  "myEvent1")
                myEvent1Handler = func;   

            if (event  ==  "myEvent2")
                myEvent2Handler = func;      
        },

        // public  methods
        method1: function (p) {
            alert('method1 says:' + p);
            MODULE.myEvent1();
        },
        method2: function  (p) {
             alert('method2 doing  stuff');
             localFunc(p);
            MODULE.myEvent2();
        }

    };
}();

// register for events
MODULE.addListener("myEvent1",function(){alert('fired1');});  
MODULE.addListener("myEvent2",function(){alert('fired2');});  

// use module (only event1 should fire!)
MODULE.method1("hello");  

Try it out:

http://jsfiddle.net/RqusH/3/

Seems like a lot of work to have myEventx, myEventHandlerx, and addListener?

Share Improve this question edited Nov 11, 2011 at 20:57 Rob W 349k87 gold badges807 silver badges682 bronze badges asked Nov 11, 2011 at 20:48 Carol SkellyCarol Skelly 362k91 gold badges735 silver badges646 bronze badges 3
  • 1 When you call addListener(), isn't that creating myEvent1Handler or myEvent2Handler as global variables referencing the func parameter passed in? It won't be setting the properties of the same name already defined in your object unless you say this.myEvent1Handler = ... - and then this.myEvent1Handler() in your myEvent1 function. (Or MODULE.myEvent1Handler like how you have MODULE.myEvent1() in method1.) – nnnnnn Commented Nov 11, 2011 at 20:53
  • What problem are you actually trying to solve? This seems like a lot of overhead that doesn't actually do anything but make a scaffolding. Perhaps if we knew what you were actually trying to accomplish, we could help you find the best way to do that. – jfriend00 Commented Nov 11, 2011 at 21:23
  • Thanks... I want eventing in MODULE, so that a user of MODULE can hook into events. MODULE methods will have async requests (using jquery) so I want to use events to indicate when a async request has completed. – Carol Skelly Commented Nov 11, 2011 at 22:27
Add a comment  | 

2 Answers 2

Reset to default 9

Normally, I wouldn't respond to an architectural question with a specific implementation (especially one dependent on a 3rd-party library like jQuery), but since my implementation promotes reusability — and we are talking patterns here — I will present a small jQuery plugin, $.eventable, which augments JavaScript objects with jQuery's event methods.

This plugin will allow you to implement event handling capability on any object (or class instance) with one simple call.

jQuery.eventable = function (obj) {
  // Allow use of Function.prototype for shorthanding the augmentation of classes
  obj = jQuery.isFunction(obj) ? obj.prototype : obj;
  // Augment the object (or prototype) with eventable methods
  return $.extend(obj, jQuery.eventable.prototype);
};

jQuery.eventable.prototype = {

  // The trigger event must be augmented separately because it requires a
  // new Event to prevent unexpected triggering of a method (and possibly
  // infinite recursion) when the event type matches the method name
  trigger: function (type, data) {
    var event = new jQuery.Event(type); 
    event.preventDefault();                
    jQuery.event.trigger(event, data, this);
    return this;
  }
};

// Augment the object with jQuery's event methods
jQuery.each(['bind', 'one', 'unbind', 'on', 'off'], function (i, method) {
  jQuery.eventable.prototype[method] = function (type, data, fn) {
    jQuery(this)[method](type, data, fn);
    return this;
  };
});

If you include that snippet, you can implement your solution like this:

var MODULE = function() {

  //  private
  var _field1;
  var _field2;

  function localFunc(p) {
    alert('localFunc');
  }

  //  public
  return $.eventable({

    // properties
    prop1: _field1,

    // public  methods
    method1: function(p) {
      alert('method1 says:' + p);
      this.trigger('myEvent1');
    },

    method2: function(p) {
      alert('method2 doing  stuff');
      localFunc(p);
      this.trigger('myEvent2');
    }

  });
} ();

// register for events
MODULE.on("myEvent1", function() {
  alert('fired1');
});
MODULE.on("myEvent2", function() {
  alert('fired2');
});

// use module (only event1 should fire!)
MODULE.method1("hello");

Your MODULE now has the following callable methods:

MODULE.on(event, /* data, */ handler);
MODULE.bind(event, /* data, */ handler);
MODULE.one(event, /* data ,*/ handler);
MODULE.off(event, handler);
MODULE.unbind(event, handler);
MODULE.trigger(event /*, data */);

Where event is a space-delimited list of events, handler is your callback, and data is an optional value to pass to your callbacks.

You can refer to jQuery's documentation for more details.

The revealing module pattern has you returning an anonymous object. If you instead declare it as a variable and return it it means you can use the standard jQuery event methods quite easily, both inside the module for raising events and externally to respond to them. Note that you do have to turn it into a jQuery object beforehand.

var controller = (function()
{
  function doAThing()
  {
    // Things getting done here
    $(interface).trigger("complete");
  }

  var interface = {
    doAThing: doAThing
  };
  return interface;
})();

$(controller).on("complete", function() { console.log("Thing Done"); });
controller.doAThing();
发布评论

评论列表(0)

  1. 暂无评论