Observer Design Pattern in JavaScript
Tags: javascript, webdev, beginners, programming
Published: 2021-08-09 09:46:15



While working with any language, we tend to use several reusable design solutions to commonly occurring problems. In JavaScript, too, we have a mix of well-defined patterns.

The Observer pattern is one of them.

In this article, we shall understand more about the Observer design pattern in JavaScript and implement a small example in vanilla JavaScript.

------

## What Is the Observer Design Pattern?

The Observer pattern follows a subscription model. A subscriber (commonly referred to as ***the observer***) subscribes to an event or an action handled by a publisher (commonly referred to as ***the subject***) is notified when the event or action occurs.

The subject broadcasts the occurrence of the event or action to all the observers.

When the observer no longer wishes to be notified of the changes by the subject, it unsubscribes itself from the subject, and the subject then removes it from the list of subscribers.

An Observer design pattern is very similar to a ***Publisher/Subscriber*** pattern, with a small difference that a ***Publisher/Subscriber*** pattern also specifies a topic it wants to subscribe to. 

For example, when detecting keyboard shortcuts, the subscriber can choose to specify a key combination that it wants to listen to in a ***Publisher/Subscriber*** model.

------
## Implementation of the Observer Pattern

As an example of the Observer pattern, we will go about implementing a simple interaction where multiple elements listen to the mouse position on the screen and perform different actions.

Below is an example of what our interaction looks like:

![Demo interaction](https://cdn.hashnode.com/res/hashnode/image/upload/v1628501304147/iFGHMMHk4.gif)

Before we implement this interaction, let us analyze what is happening in this example as the mouse position changes.

* The mouse position is immediately updated in the textbox at the top right corner.

* The circle follows the trajectory of the mouse after a delay of 1s.

From the above description, we see that multiple components need information about the same thing but behave differently.

From the above example, we identify that the **subject** listens to the mouse event on the window and relays it to whoever wants it. The **circle and textbox** are **observers** in the above example.

So let us now go ahead and implement it.

### Step 1. Implement a MousePositionObservable class

As a first step let us go ahead and implement the `MousePositionObservable` class. This class needs to do the following things:

* Keep a list of observer callbacks.

* Expose a `subscribe` method which the observers will call to subscribe to the change. The return value of this must be a function that will move the `callback` from the set of `subscriptions` when called.

* Listen to `mouseMove` event and trigger all subscription callbacks.

The code looks like the below:

```javascript
class MousePositionObservable {
  constructor() {
    this.subscriptions = [];
    window.addEventListener('mousemove',this.handleMouseMove);
  }
  handleMouseMove =  (e) => {
     this.subscriptions.forEach(sub => sub(e.clientX, e.clientY));
  }
  subscribe(callback) {
    this.subscriptions.push(callback);    
    
    return () => {
      this.subscriptions = this.subscriptions.filter(cb => cb !== callback);
    }
  }
}
```

### Step 2. Create HTML elements

We now create our HTML elements for `circle` and `textMessageBox` and add styles to them.

```html
<div class="container">
  <div class="circle" ></div>
  <div class="mouse-position">
  <h4>Mouse Position</h4>
  <div class="position"></div>
</div>
</div>

```

```css
.container {
  position: relative;
  width: 100vw;
  height: 100vh;
  background-color: #f3df49;
}
.circle {
  position: absolute;
  background-color: #238643;
  width: 25px;
  height: 25px;
  border-radius: 50%;
  z-index: 2;
}

.mouse-position {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 200px;
  height: 100px;
  background-color: black;
  border-radius: 4px;
  padding: 4px 16px;
  color: white;
}

.mouse-position h4 {
  color: white;
  margin: 10px 0;
}
```

### Step 3. Add observers

The last step to make it come together is to create an instance of our `MousePositionObservable` class and add observers to it.

To do that we shall invoke the `subscribe` method on the class instance and pass on a callback.

Our code looks like the below:

```javascript
const mousePositionObservable = new MousePositionObservable();

mousePositionObservable.subscribe((x, y) => {
  const circle = document.querySelector('.circle');
   window.setTimeout(() => {
     circle.style.transform = `translate(${x}px, ${y}px)`;
   }, 1000);
});

// Update the mouse positon container to show the mouse position values
mousePositionObservable.subscribe((x, y) => {
  const board = document.querySelector('.mouse-position .position');
  board.innerHTML = `
    <div>
       <div>ClientX: ${x}</div>
       <div>ClientY: ${y}</div>
    </div>
  `
})
```

We add two subscriptions to the `MousePositionObservable` instance, one for each element that needs to listen to mouse values.

The subscription callback for the `circle` element gets the reference of the DOM element and updates its `transform` property. The transform property will use hardware acceleration where possible, so using `translate()` over position top and left will see performance benefits if any animations or transitions are also being used on the element.

The subscription callback for the `textbox` element updates its HTML content by using the `innerHTML` property.

> Note: When you want to unsubscribe the listener, all you have to do is to store the returned value from the subscribe function call and invoke it like a function

That is all we need for our demo.

You can check out the working example in the Codepen below:

{% codepen https://codepen.io/mayank_shubham/pen/OJpjraX %}

------

## Advantages and Disadvantages of the Observer Design Pattern

An Observer design pattern provides us the following benefits:

* It is extremely useful when we want to perform multiple actions on a single event.

* It provides a way to decouple functionalities while maintaining consistency between related objects.

The downside of this pattern stems from its benefits:

* Since the Observer design pattern leads to loosely coupled code, it is sometimes hard to guarantee that other parts of the application are working as they should. For example, the subscriptions added to the subject may have code that is behaving incorrectly, but there is no way for the publisher to know that.

-------

## Real-World Applications

While working with web development we see that `Redux` and `React Context` are both examples of implementations built upon the Observer Design Pattern.

In Redux, we have a `subscribe` method that allows us to add observers to the redux state which acts as the subject. Whoever subscribes to the redux store is notified when any change is made to the store.

Similarly, with React Context whenever the value is updated for the `ContextProvider`, all components that subscribe to the Context either through the `useContext` hook or through `Context.Consumer` are re-rendered with updated context values.

--------
## Conclusion

In this article, we went through the Observer design pattern and how to use it within our application. We also implement a demo based on this pattern and learned about some of the advantages and disadvantages of following this approach to designing interactions.

**Thank you for reading.**

If you found this article useful and informative, please don't forget to like and share it with your friends and colleagues.

If you have any suggestions, please feel free to comment.

Follow me on [Twitter](https://twitter.com/ShubhamReacts) for more web development content.