views:

66

answers:

1

I've been implementing a form of a publisher/subscriber design pattern in jQuery. I'm basically building classes in Javascript utilizing CoffeeScript that serve as components on my page. i.e. Navigation, DataList, etc.

Instead of having DOM elements fire events, I have instances of these classes that use trigger on themselves to send custom events. These instances can then listen to each other and can update the DOM elements they own accordingly based on the changes in each others behavior!

I know this works as I have one of my components dispatching a custom event properly. However, I've ran into a snag. I've created another component and for the life of me I cannot figure out why it's event is not being fired.

This is the implementation of my class:

window.List = (function() {
    List = function(element, settings) {
      var _a, _b, _c;
      this.list = $(element);
      this.settings = jQuery.extend(List.DEFAULTS, settings);
      this.links = this.list.find(this.settings.link_selector);
      this.links.selectable();
      _b = [SelectableEvent.COMPLETED, SelectableEvent.UNDONE, SelectableEvent.SELECTED, SelectableEvent.DESELECTED];
      for (_a = 0, _c = _b.length; _a < _c; _a++) {
        (function() {
          var event_type = _b[_a];
          return this.links.bind(event_type, __bind(function(event, selectable_event) {
            return this.dispatch(selectable_event);
          }, this));
        }).call(this);
      }
      return this;
    };
    List.DEFAULTS = {
      link_selector: "a",
      completed_selector: ".completed"
    };
    List.prototype.change = function(mode, previous_mode) {
      if (mode !== this.mode) {
        this.mode = mode;
        if (previous_mode) {
          this.list.removeClass(previous_mode);
        }
        return this.list.addClass(this.mode);
      }
    };
    List.prototype.length = function() {
      return this.links.length;
    };
    List.prototype.remaining = function() {
      return this.length() - this.list.find(this.settings.completed_selector).length;
    };
    List.prototype.dispatch = function(selectable_event) {
      $(this).trigger(selectable_event.type, selectable_event);
      return alert(selectable_event.type);
    };
    return List;
}).call(this);

Pay attention to:

List.prototype.dispatch = function(selectable_event) {
    $(this).trigger(selectable_event.type, selectable_event);
    return alert(selectable_event.type);
};

This code is triggered properly and returns the expected event type via an alert. But before the alert it is expected to trigger a custom event on itself. This is where I'm encountering my problem.

$(document).ready(function() {
    var list_change_handler, todo_list;
    todo_list = new List("ul.tasks");
    list_change_handler = function(event, selectable_event) {
      return alert("Hurray!");
    };
    $(todo_list).bind(SelectableEvent.COMPLETED, list_change_handler);
    $(todo_list).bind(SelectableEvent.UNDONE, list_change_handler);
    $(todo_list).bind(SelectableEvent.SELECTED, list_change_handler);
    $(todo_list).bind(SelectableEvent.DESELECTED, list_change_handler);
}

You see here the alert "Hurray" is what I want to fire but unfortunately I am having no luck here. Ironically I've done the exact same thing with another class implemented the same way dispatching a custom event and the listener is receiving it just fine. Any ideas on why this wouldn't work?

Update:

Per discussing in the comments, it looks like Logging "this" in console returns the JS Object representing the class. But logging "$(this)" returns an empty jQuery object, thus trigger would never be fired. Any thoughts on why $(this) is coming up empty when "this" is accurately returning the instance of the class?

+1  A: 

I found out that jQuery could not index my object because the class implemented it's own version of a jQuery method. In this case, length(). Renaming the length() method to total() resolved the problem completely and any instance of the class can successfully trigger events.

Jim Jeffers
Interesting and well spotted. Reminds me of the classic IE foible: Giving a button the ID "submit"
Sorpigal