Observer/Observable example in javascript

by spoike

HTML

<ul class="log">
  <li class="head">
    Log entries
  </li>
</ul>

CSS

ul.log {
  padding: 10px;
  background-color: #efefef;
  font-family: Arial, sans-serif;
}

ul.log li {
  padding: 10px;
  background-color: #fff;
  border-top: dashed black thin;
}

ul.log li.head {
  font-weight: bold;
  border-top: none;
}

JavaScript

var log = function(entry) {
  $log = $('ul.log');
  $log.append('<li>' + entry + '</li>');
};

var observable = function(v) {
  var val = v, subscribers = [];
  
  // the observable object
  var output = {
    
    // subscribes to event
    onChange : function(func) {
      subscribers.push(func);
      return output; // enables chaining
    },
    
    // the method that changes the observable object
    // and emits the event
    set : function(v) {
      var i;
      val = v;
      for (i = 0; i < subscribers.length; i++) {
        // this is hardly fault tolerant but as long 
        // as subscribers are functions it'll work
        subscribers[i](v);
      }
      return output;
    },
    
    // the method emits an event with given message,
    // useful when the observable is a complex
    // object
    emit : function(msg) {
      var i;
      for (i = 0; i < subscribers.length; i++) {
        subscribers[i](msg, output);
      }
      return output;
    },
    
    // removes subscription
    off : function(func) {
      // idiomatic JS for removing objects in array
      var index = subscribers.indexOf(func);
      subscribers.splice(index, 1);
      return output;
    }
    
  };
  
  return output;
  
};

// the subject
var component = {
  
  leet : observable(1336),
  cat : observable("kitty!")
  
};

// example of a callback that is removable
var removableFunc = function(v) {
  log("{ <b><i>this function will be removed</i></b> }");
}

// Usage (on variables):
component.leet.onChange(function(v) {
  log("leet has changed to: " + v);
}).
onChange(function(v) {
  log("and it was leet");
});

component.cat.onChange(function(v) {
  log("cat has changed to: " + v);
}).onChange(function(v) {
  log("and it was awesome");
}).onChange(removableFunc);

component.leet.set(1337);
component.cat.set("cats!");

component.cat.off(removableFunc);

component.cat.set("kitties!");

// Usage (on component-wide updates)

// the subject, the component itself
var...