Click here to Skip to main content
Click here to Skip to main content

Observer Design Pattern Using JavaScript

By , 26 Apr 2006
 

Introduction

Anyone who has ever worked with JavaScript for any amount of time should be familiar with the task of creating custom JavaScript objects. People who are not familiar with OOP in JavaScript can read a brief introduction about it here. This article deals with the implementation of the Observer pattern using JavaScript.

A brief introduction to JavaScript

JavaScript is a prototype-based scripting language (originally called LiveScript) with a syntax loosely based on C, developed by Netscape Communications, for use with the Navigator browser. Like C, the language has no input or output constructs of its own. Where C relies on standard I/O libraries, the JavaScript engine relies on a host environment into which it is embedded. This scripting language accommodates what other languages might call procedures, subroutines, and functions, all in one type of structure: the custom function. One major use of web-based JavaScript is to interact with the Document Object Model (DOM) of a web page to perform tasks not possible using HTML alone. JScript is the Microsoft equivalent of Netscape's JavaScript, for use with Microsoft's Internet Explorer.

Create a custom object in JavaScript

Creating a new JavaScript object consists of two steps. First, you need to create a function whose name will be the name of the new class. This function is typically referred to as a constructor. Second, you have to create as instance of the object using the new operator followed by the object name and any parameters it requires. The following code defines a Person function, and then creates a Person object using the new operator:

function</CODE> Person( name, surname )
{
   this.name    = name;
   this.surname = surname;
}

var salvo = new Person( ‘Salvatore’, ‘Vetro’ );

this points to the current object instance with which you are working, thus allowing you to add and modify properties on the object.

How can you add a method to an object?

In JavaScript, every object that can be created by calling a constructor function has an associated prototype property. The syntax for adding a new method is:

customeObject.prototype.newMethodName = function;

// Specific case

Person.prototype.Speak = function(){...}

If you add a method to the prototype for an object, then all objects created with that object's constructor function will have that new method. Note that prototype is itself an object, and can be assigned properties and methods via the object literal syntax:

function NewObject()
{
   alert("I am a new object.");
}

NewObject.prototype = 
{
   alert1: function(str){alert(str);}, //new method

   name: 'As you want', //new property

   alert2: function(){alert("Bye.");} //new method
};

var newObject = new NewObject();

newObject.alert1("Ciao");

newObject.name;

newObject.alert2();

Each time your script attempts to read or write a property of an object, JavaScript follows a specific sequence in search of a match for the property name. The sequence is as follows:

  • If the property has a value assigned to the current (local) object, this is the value to use.
  • If there is no local value, check the value of the property’s prototype of the object’s constructor.
  • Continue up the prototype chain until either a match of the property is found (with a value assigned to it) or the search reaches the native Object object. Therefore, if you change the value of a constructor’s prototype property and you do not override the property value in an instance of that constructor, JavaScript returns the current value of the constructor’s prototype property.

Observer Design Pattern class diagram

The Observer design pattern defines a one-to-many dependency between a subject object and any number of observer objects, so that when the subject object changes state, all its observer objects are notified and updated automatically.

  • Participants
    • Subject
      • Knows its observers. Any number of Observer objects may observe a Subject.
      • Provides an interface for attaching and detaching Observer objects.
    • Observer
      • Defines an updating interface for objects that should be notified of changes in a Subject.
    • ConcreteSubject
      • Stores the state of interest to ConcreteObserver objects.
      • Sends a notification to its observers when its state changes.
    • ConcreteObserver
      • Maintains a reference to a ConcreteSubject object.
      • Stores state that should stay consistent with the subject's.
      • Implements the Observer updating interface to keep its state consistent with the Subject's.
  • Collaborations
    • ConcreteSubject notifies its observers whenever a change occurs that could make its Observers' state inconsistent with its own.
    • After being informed of a change in the concrete subject, a ConcreteObserver object may query the subject for information. ConcreteObserver uses this information to reconcile its state with that of the Subject.

Observer Design Pattern sequence diagram

The following interaction diagram illustrates the collaborations between a Subject and two Observers:

The Observer object that initiates the change request postpones its update until it gets a notification from the Subject. Notify is not always called by the subject. It can be called by an Observer or by another kind of object entirely.

What are we going to do?

Now you know what the Observer design pattern is and how you can create custom objects using JavaScript. As you can see in the class diagram, you have to define two methods (Attach and Detach) inside the Observer class. To do that, you need a collection to perform attach/detach operations. It is time to write your first JavaScript ArrayList. First of all, you have to define what the ArrayList should be able to do.

Count - Add - GetAt - Clear - RemoveAt - Insert - IndexOf - LastIndexOf.

function ArrayList()
{
   this.aList = []; //initialize with an empty array
}
        
ArrayList.prototype.Count = function()
{
   return this.aList.length;
}
        
ArrayList.prototype.Add = function( object )
{
   //Object are placed at the end of the array
   return this.aList.push( object );
}

ArrayList.prototype.GetAt = function( index ) //Index must be a number
{
   if( index > -1 && index < this.aList.length )
      return this.aList[index];
   else
      return undefined; //Out of bound array, return undefined
}
        
ArrayList.prototype.Clear = function()
{
   this.aList = [];
}

ArrayList.prototype.RemoveAt = function ( index ) // index must be a number
{
   var m_count = this.aList.length;
            
   if ( m_count > 0 && index > -1 && index < this.aList.length ) 
   {
      switch( index )
      {
         case 0:
            this.aList.shift();
            break;
         case m_count - 1:
            this.aList.pop();
            break;
         default:
            var head   = this.aList.slice( 0, index );
            var tail   = this.aList.slice( index + 1 );
            this.aList = head.concat( tail );
            break;
      }
   }
}

ArrayList.prototype.Insert = function ( object, index )
{
   var m_count       = this.aList.length;
   var m_returnValue = -1;

   if ( index > -1 && index <= m_count ) 
   {
      switch(index)
      {
         case 0:
            this.aList.unshift(object);
            m_returnValue = 0;
            break;
         case m_count:
            this.aList.push(object);
            m_returnValue = m_count;
            break;
         default:
            var head      = this.aList.slice(0, index - 1);
            var tail      = this.aList.slice(index);
            this.aList    = this.aList.concat(tail.unshift(object));
            m_returnValue = index;
            break;
      }
   }
            
   return m_returnValue;
}

ArrayList.prototype.IndexOf = function( object, startIndex )
{
   var m_count       = this.aList.length;
   var m_returnValue = - 1;
            
   if ( startIndex > -1 && startIndex < m_count ) 
   {
      var i = startIndex;

      while( i < m_count )
      {
         if ( this.aList[i] == object )
         {
            m_returnValue = i;
            break;
         }
                    
         i++;
      }
   }
            
   return m_returnValue;
}
        
        
ArrayList.prototype.LastIndexOf = function( object, startIndex )
{
   var m_count       = this.aList.length;
   var m_returnValue = - 1;
            
   if ( startIndex > -1 && startIndex < m_count ) 
   {
      var i = m_count - 1;
                
      while( i >= startIndex )
      {
         if ( this.aList[i] == object )
         {
            m_returnValue = i;
            break;
         }
                    
         i--;
      }
   }
            
   return m_returnValue;
}

Well done! Now you can create both the Observer class and the Subject class of the Observer design pattern.

Observer class of the Observer Design Pattern

You just have to define the method Update.

function Observer()
{
   this.Update = function()
   {
      return;
   }
}

Subject class of the Observer Design Pattern

OK, let's go define the three main methods: Notify, AddObserver, and RemoveObserver.

function Subject()
{
   this.observers = new ArrayList();
}

Subject.prototype.Notify = function( context )
{
   var m_count = this.observers.Count();
            
   for( var i = 0; i < m_count; i++ )
      this.observers.GetAt(i).Update( context );
}

Subject.prototype.AddObserver = function( observer )
{
   if( !observer.Update )
      throw 'Wrong parameter';

   this.observers.Add( observer );
}

Subject.prototype.RemoveObserver = function( observer )
{
   if( !observer.Update )
      throw 'Wrong parameter';
   
   this.observers.RemoveAt(this.observers.IndexOf( observer, 0 ));
}

Inheritance in JavaScript

There are some methods to simulate inheritance using JavaScript. A very simple way is to define a simple method called inherits that you can use to copy all the properties and methods of an object to another object.

function inherits(base, extension)
{
   for ( var property in base )
   {
      try
      {
         extension[property] = base[property];
      }
      catch( warning ){}
   }
}

A simple implementation

Now you need to implement a client so that you can attach observers to the concrete subject. For example, you could create a simple application that defines a main checkbox as observable and some checkboxes as observers. When the concrete subject will change its own state, it is going to notify what happened to the observers. Any observer being decoupled from the subject will manage, independently of each other, the notification.

/************* Concrete Subject *************/

var mainCheck = document.createElement("INPUT");

mainCheck.type = 'checkbox';
mainCheck.id   = 'MainCheck';
            
inherits(new Subject(), mainCheck)

mainCheck["onclick"] = new Function("mainCheck.Notify(mainCheck.checked)");
/**************** Observer ****************/</CODE>

var obsCheck1 = document.createElement("INPUT");
var obsCheck2 = document.createElement("INPUT");

obsCheck1.type = 'checkbox';
obsCheck1.id   = 'Obs1';

obsCheck2.type = 'checkbox';
obsCheck2.id   = 'Obs2';
            
inherits(new Observer(), obsCheck1)
inherits(new Observer(), obsCheck2)

obsCheck1.Update = function(value)
{
   this.checked = value;
}

obsCheck2.Update = function(value)
{
   this.checked = value;
    
   //Add ........
}
            
mainCheck.AddObserver(obsCheck1);
mainCheck.AddObserver(obsCheck2);

Enclosed example

In the specific case, any Observer manages the notification in the same manner. When the concrete Subject notifies the Observers about the new state, any Observer changes its own state using the observable state as its new value.

Collaboration

This article could be improved. Please contact me for any suggestions.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Salvatore Vetro
Web Developer
Italy Italy
Member
Salvo is a software architect working in Milan, Italy.
 
He enjoys design infrastructures based on object oriented paradigm.
At the moment he is managing the integration of “ERP Business Processes” with other applications developing designing business services that are service-oriented architecture compliant.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalexcellentmembermagiccoder1 Jan '13 - 23:12 
excellent... Big Grin | :-D
QuestionObserver Patternmembersoumya Ranjan Nayak14 Sep '12 - 3:17 
good for beginers
GeneralMy vote of 4memberRupeshKumar21 Sep '11 - 6:05 
Idea is good but bit complecated. You could have used jquery utility methods to minimize the complexity and lines of codes. Your major focus is design pattern not the utility methods....
GeneralMy vote of 5membergary.flu917 Jan '11 - 22:55 
Just what I want!!
GeneralA contribution [modified]memberIngemar Nilsson30 May '07 - 1:49 
Really excellent, very good!
 
Here is a small contribution.
A simple "Remove(obj)" method than can be added to the ArrayList.
[code below:]
 
ArrayList.prototype.Remove = function ( obj ){
      var index = 0;
      while(index >= 0){
            index = this.IndexOf(obj, 0);           
            if (index >= 0)
                  this.RemoveAt(index);
      }
}

GeneralExcellent..memberMeysam Gharanfoli21 May '07 - 23:23 
Smile | :) Excellent..
 
Meysam Gharanfoli

GeneralAnonymous function observersmemberBen Allfree6 Oct '06 - 4:13 
My humble contribution to improving the article:
 
function Observer(func)
{
this.func = func;
this.Update = function()
{
this.func();
return;
}
}
 
This allows you to do:
 
new Observer(function() { alert('Hello, world'); });
 

GeneralSlight problem in Opera 9memberFranck Quintana8 Sep '06 - 14:59 
First of all, very interesting article.
I like this approach and it's another proof that javascript is a really amazing language.
The sample works well under Firefox 1.5.0.6 and IE 6.0.
In Opera 9.01 I lost the synchronization if I click rapidly.
 
Great job indeed.
 
Franck Quintana
QuestionObserver ClassmemberDFU2321 Jul '06 - 5:37 
In the base Observer class what is the point of defining an Update function that will always (should always) be overwritten/overridden by the inheriting/implementing class? Is it just to mimic the observer pattern where classes will implement the interface of an Observer?
 
I just want to make sure that I understand the code in your example and that I understand what all is going on with the event flow. Can you possibly give another real world example of where this could be beneficial in a web application?
 
Thanks for great the article!
 

 

 
Wally Atkins
Newport News, VA, USA
http://wallyatkins.com

GeneralTake my 5memberHimaBindu Vejella9 Jul '06 - 22:56 
Couldn't stop from rating it as 5.
Good work Keep it up
 
"Aim to go where U have never been B4 and Strive to achieve it"
http://groups.yahoo.com/subscribe/dotnetforfreshers
http://himabinduvejella.blogspot.com

AnswerRe: Take my 5 [modified]memberSalvatore Vetro17 Jul '06 - 5:25 
Thank you very much. Big Grin | :-D
GeneralExcellent..memberRajesh Pillai6 May '06 - 0:55 
Another gem in my code library...
You got my 5 points...
 
Enjoy Life,
Rajesh Pillai
http://rajeshpillai.blogspot.com/

JokeRe: Excellent..memberSalvatore Vetro7 May '06 - 5:42 
Thank you very much Rajesh.
Any suggestion? I would like to improve it.
JokeExcellentmemberLimeyRedneck5 May '06 - 6:16 
Very nice article, very readable and deals with the need very well.
 
This should help all the folks dealing with AJAX and interactive web designs very nicely.
 

 

 
Nothing is impossible, we just don't know the way of it yet.
JokeRe: ExcellentmemberSalvatore Vetro5 May '06 - 9:26 
Thank you very much
Generalhelp me create treeview with asp.net C#memberchunglvcit4 May '06 - 23:10 
BLOGID BLOGNAME PARENTID
1 aaa NULL
4 ccc 1
6 ccc 1
7 aaa NULL
9 ccc 7
10 DDD 9

I want display treeview by asp.net with C# , if every body sample code help me.

GeneralThe dark side of the Observer PatternmemberAlejandro Xalabarder30 Apr '06 - 2:57 
Hi Salvatore, this is not a criticism to your article but
simply my opinion about the Observer Pattern. By the way you could include some reference to the source (Design Patterns.. of Erich Gamma). I've found this link to the original chapter, it is an example chapter so I don't know how long will be valid: http://www.research.ibm.com/designpatterns/example.htm[^].
 
What is wrong with the Observer Pattern? The motivation of the pattern is simple to understand and to enunciate: several objects wants to be informed about something that happens in another object. Yet the Object Oriented (OO) solution (Observer Pattern) is complicated, intrusive and requires a lot of code to prepare the subject. For instance, take a look at the bigest coding part of this article, it is to handle a list of observers! This handling is always the same: add, remove etc but it has to be programmed for each thing to be observed (at least in C++ and in java).
 
It is not that it could be a better solution in OO. In my opinion the Observer Pattern demonstrates a big limitation in the expressivity of the OO. Other architectures solves this problem in a easier way (i.e. signal and slots in Qt http://doc.trolltech.com/3.3/signalsandslots.html[^]) although they might also have their drawbacks.
 
Cheers
Alejandro

AnswerRe: The dark side of the Observer PatternmemberSalvatore Vetro2 May '06 - 1:45 
Hi Alejandro,
Thank you very much for your message.
 
"Signals and Slots" are a generalized implementation of the Observer pattern.
 
A signal is an observable event, or at least notification that the event happened.
 
A slot is a potential observer, typically in the form a function to be called.
 
You connect a signal to a slot to establish the observable-observer relationship.
 
There are three costs of which you need to be aware. A signal-to-slot call:
 
1. May take more time/space than a direct function call
2. Probably can't be inlined
2. May not be as clear to a reader of the code
 
I have never said observer design patter is the better solution for any occasion. I just explained as you can use it. People have to decide when should use it.
 
Regards,
 
Salvatore Vetro
 

 

 
-- modified at 10:36 Tuesday 2nd May, 2006
GeneralRe: The dark side of the Observer PatternmemberAlejandro Xalabarder2 May '06 - 12:13 
Hi Salvatore,
 
"Signal & Slot implement the Observer Pattern", I use also to say the same sentence, therefore we agree basically at this point. It is just a small interpretation problem. There are two different things:
1) the Observer/Observable problematic which can be solved in many ways
and
2) the solution of (1) described by Erich Gamma in "Design Patterns. Elements of Reusable Object-Oriented Software" 1995.
 
In my message I called "Observer Pattern" to the solution in Object Oriented aproach (2). I think it is the right interpretation, it can be seen in the chapter dedicated in this book to the Observer Pattern (first link of my 1st message). It can be seen that where he talks about "Observer Pattern" it is only applicable to his solution and not to the generic problem.
 
I am not a developer of Signal&Slots Qt, I mention it only as example. You expose some drawbacks (costs) of this mechanism but, in my opinion, the Observer Pattern is not better in any of them.
 
I work with the Observer Pattern the most of the times, in java and in C++. I have no problem with it, simply I have an opinion that's all.
 
friendly regards,
Alejandro
 

JokeRe: The dark side of the Observer PatternmemberSalvatore Vetro2 May '06 - 22:15 
Hi Alejandro,
I have never said the observer design pattern is the best.
I just talk about it. I think observer is good in some occasions and Signal&Slots in some others. Instead: why don't you help me to improve the article?
 
friendly friendly friendly regards,
Salvo
 


GeneralRe: The dark side of the Observer PatternmemberAlejandro Xalabarder3 May '06 - 9:26 
Hi Salvo,
maybe I shouldn't post my messages in this place, sorry if it is also your opinion. I didn't want to annoy nobody, and also not critize you or your article. I am very new in these forums, I will improve with the time!;). Please let me know if you prefer that I delete my messages from your article.
 
Ciao
Alejandro
 

AnswerRe: The dark side of the Observer PatternmemberSalvatore Vetro3 May '06 - 10:10 
Hi Alejandro,
An opinion is an opinion.
I respect you and that you wrote.
You shouldn't remove your messages.
 
Thank you very much for your contribution.
 
Ciao,
 
Salvo Big Grin | :-D
GeneralRe: The dark side of the Observer Patternmemberamysimple21 Aug '06 - 22:56 
amysimple said
GeneralRe: The dark side of the Observer PatternmemberSerban Murariu30 Aug '06 - 20:35 
Hey guys,
your discution is interesting and instructive to read. Yet my opinion is that the observer pattern is easier to understand for beginers. So maybe you two should write a second part of the article about the generalization of the pattern.
 
Cheers
GeneralHmm....memberHyperX28 Apr '06 - 11:48 
I like the code, I like the way its presented. I like everything about this.
 
Just a small question though... Why did you have to write the observer pattern in JS? What were your circumstances? Why not in C# or vb.net etc?
 
Thanks,
 
HyperX.
GeneralRe: Hmm....memberkemetokara30 Apr '06 - 18:40 
I think I can answer this one for the author with an example. Let's say I had some custom JavaScript code (like a JavaScript tree control or menu for instance). I wanted to have certain JavaScript functions fired off when the document loads, but I would not have access to the programmer's body tag that has an attribute called "onload". The "onload" event waits until the webpage fully loads before it calls my functions to ensure that any HTML objects my functions would call are created and available for use.
 
I also don't want to have the programmer that may be using my JavaScript control to have to add custom functions to the body tag's onload event attribute for every page he/she needs to use my menu. If I want to call the "onload" function programmatically from my code, I can only attach one function to the be run by the "onload" event. This function, using the observer pattern, would go through all the functions that want to be notified and run them in order when the "onload" event occurs.
 
I have found the observer pattern to be extremely useful in this case and many others when doing complex client side tasks in JavaScript. Hope that clears it up.

 
Charles T
GeneralRe: Hmm....memberHyperX1 May '06 - 6:46 
Thanks for the time,
 
That helps me understand it even better.
 
HyperX.
JokeRe: Hmm....memberkemetokara1 May '06 - 13:01 
Not a problem Big Grin | :-D
 
Charles T
GeneralRe: Hmm....memberSalvatore Vetro1 May '06 - 21:17 
Thank You For Your Help Charles Cool | :cool:
JokeRe: Hmm....memberkemetokara2 May '06 - 5:30 
Thanks for the article! I gave it a 5!
 
Charles
JokeRe: Hmm....memberSalvatore Vetro2 May '06 - 5:37 
Thank you very much Charles.
Please contact me when you want for any suggests.
 
Ciao,
 
Salvo
GeneralWell thought, well written.membervolkan.ozcelik27 Apr '06 - 22:50 
Observer design pattern is a life-saver on OOP-based server-side enterprise applications.
 
With the introduction of AJAX and fat-client applications the necessity of both UI-design and code-design patterns "on the client side" increased considerably.
 
Needless to say, you got my five.
 
.: Volkan Ozcelik :. blog .: trials/errors/studies :. sardalya .: orkinos :.
JokeRe: Well thought, well written.memberSalvatore Vetro3 May '06 - 2:00 
Thank you very much
GeneralVery nice articlemembertkrafael_net27 Apr '06 - 6:43 
The people dont know the power of javascript language. There are so many resources...
You take my five. Nice article Smile | :) Big Grin | :-D Laugh | :laugh:
AnswerRe: Very nice articlememberSalvatore Vetro27 Apr '06 - 21:51 
Thank you very much.
Please contact me for any suggests.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 26 Apr 2006
Article Copyright 2006 by Salvatore Vetro
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid