Communicate between Angular Components... With Encapsulation!
Tags: angular, tutorial, webdev, oop
Published: 2020-08-27 21:40:20

I saw a post here the other day by [Nicolas LARRODE](https://dev.to/nik0w) titled ['Communicate between Angular components'](https://dev.to/nik0w/communicate-between-angular-components-4l3d).  There he described how one can communicate between two components using a service that exposes a Subject. 

I won't recreate his entire post here, but you can check it out at the link above, or see (my recreation of) the resulting app [here](https://stackblitz.com/edit/angular-itfpzv).

Essentially he creates a Subject, which is an Observable that can both be subscribed to, and made to emit (via the 'next' method.)

In my (contrived) example there are two sibling services ('brother' and 'sister'.)  each displays a message from the service.  
```
this.sharedData.data.subscribe(result => {
      this.greeting = result;
    });
```

```
Sister Says: {{greeting}} Brother!
```

That message is sent to the service by the 'app' component, and the service dutifully passes it on.  
```
this.sharedData.data.next(greeting);
```


This is a great way to share data and events between components, but there is a shortcoming.  It violates encapsulation.  Any component can send whatever message they want.  And every sender needs to know how sending is implemented.

Right now we can make brother and sister say ANYTHING to each other. But coding is all about enforcing behavior on your objects.  Otherwise why even have types?

There is a pattern called 'Observable Store' that can help us out here, and really make this data sharing a bit more robust.  

The first thing we'll do is convert our Subject to a BehaviorSubject.  It's another rxjs type that is similar to Subject, but has one great advantage: if a subscriber is late to the party, and subscribes after the observable has already emitted, they get the last emitted value.  If our object remained a regular old Subject, the new Subscriber would just have to wait for the next value.
```
private _data: BehaviorSubject<string> = new BehaviorSubject('');
```

You may notice we've also given our BehaviorSubject an initial value and made it private.  It is now hidden from our components.


We'll expose it as a property.  But not all of it, just the observable portion.
```
public get Data(): Observable<string>{
   return this._data.asObservable();
}
```
Our subscribers can now see Data.  But no one is able to write to it, they don't even know it came from a BehaviorSubject. And why should they care?!?

We'll allow them to push messages via a new method here:
```
SetGreeting(greeting: string){
    this._data.next(greeting);
}
```

This method pushes to our private BehaviorSubject _data.  The effect is that all of the subscribers to our *public* observable receive the new value.  Cool and all, but it's just the same functionality we had before.

The cool part comes when you want to change some functionality. Say we want to prevent brother and sister from bickering.  We can add this code to our new SetGreeting method:
```
SetGreeting(greeting: string){
    let filteredGreeting = greeting;
    if(greeting.toLowerCase() === 'i hate you'){
      filteredGreeting = 'I love you';
    }
    if(greeting.toLowerCase() === 'shut up'){
      filteredGreeting = 'Tell me more';
    }

    this._data.next(filteredGreeting);
  }
```
Now if we had put this code in the app component it would have worked.  But either sibling component could have overwritten it and said whatever they wanted, they could have made their SIBLING say whatever they wanted them to.  That's where the real value comes in.

here's a stackblitz if you'd like to play around with it:
https://stackblitz.com/edit/angular-qjrdry