I'm a little confused about the use of BehiavorSubject instead of using shared variables in a service. If I create a service with shared variables and even overwrite them, the angular components also detect these changes, then why should I use BehiavorSubject instead of shared variables? for example in my project I have a navigation bar that is displayed if the user is logged in so I have ngIf service.isLoggedIn and it works fine. why do I need an observable in service and subscribe to its events. If someone changes this value from a different component it will change here as well. I am new to angular let me know if I am missing something. Thank you (I am following this example: https://loiane.com/2017/08/angular-hide-navbar-login-page/)
Yes, you said it right that shared variables can be used which, in turn, can detect the changes and update the view
accordingly !
Then why do we need Subject or BehaviorSubject
?
The simple answer is,
when it is only about changing the view directly as per updated shared variable something like below,
<div>Result : {{sharedService.result}}</div>
using shared variable makes sense. So, in shared service, you just change result
to 10
and immediately view
will be updated with 10
value.
But
what when result
is 10
, in (any) component, you want to run some piece of code/logic ???
How can you make sure that when result
gets 10
value, some logic will be run (in the component ?)
something like below,
some.component.ts
if(sharedService.result === 10){
// This code can not run with shared variable approach
}
Q: Can we write something like above in component ?
A: yes
Q: After writing it, will it run the logic written inside?
A: No
Q: Why ?
A: Because, shared variables are (using service) referenced type. It means whenever you change the value, all references will be changed (for singleton service) in your application but code written in some.component.ts
won't run or trigger.
Q: Why ?
A: Because in javascript/angular, to execute such type of scenario/code, you should have a mechanism of callback
.
Q: What is callback ?
A: A function which can be passed as a parameter to any function which has ability to execute itself once the main function is executed.
That's the basic knowledge required to understand BehaviourSubject
.
Now when you define a behaviourSubject
in the service as below,
Shared.Service.ts
myBehaviorSubject = new BehaviourSubject(); // has ability to register a callback function
You can use myBehaviorSubject
in any component as below,
some.component.ts
constructor(private sharedService:SharedService){
// below subscribe line registers a callback function with myBehaviorSubject.
this.sharedService.myBehavioirSubject.Subscribe((value)=>{ // This is callback function `(value)=>{...}`
if(value === 10){ // When value gets 10 value, below code will run automatically
// This code will run when condition is met
}
})
}
Now, behaviourSubject has some extra mechanism to emit the value. So if I emit 10
value from anywhere like this.myBehaviourSubject.next(10)
, due to internal mechanism of behaviourSubject
, registered callback function will be called. As it is a function, when 10
value is emitted, a callback function will execture itself and it will run other logic written inside the function.
I hope, with this understanding you will be able to understand why shared variables
are different from behaviourSubject
That's a fair question. And based on your comment, keeping it as a variable might be the best and simplest solution. Here are a few use-cases, though, that I can think of:
To perform logic every time the value changes. You could also do this in set
function on your variable, but using RxJS gives you easy access powerful operators such as debounce
and several mapping operators. Need to make an API call every time the value changes, but you want to wait until the user is done typing before hitting your API? RxJS is a fantastic solution to that.
You can combine it with other observables. Maybe you have another stream of events. Making that variable an Observable, you can easily plug changes to the variable into that other stream.
Better Angular performance. By using a BehaviorSubject (which is a type of observable), you can put a reference to it inside of the Angular template and use the async
pipe to automatically subscribe and automatically mark it for change detection when the value changes. So it would look like this: service.isLoggedIn | async
. If you do your whole component this way, you could eventually switch the ChangeDetectionStrategy to OnPush, which is far more performant. Or even better, you could switch to the ngrxPush
pipe and move your application entirely out of Angular zones, improving performance even more.
Just remember that even though your changes "magically" update in the components, that magic comes at a cost. Angular had to figure out what changed, and don't think it figured that out on the first go. It's constantly monitoring your application-- every button click, every input, sometimes even hover events will trigger change detection. So the more you can provide hooks into what changed, and when it changed, you've made it that much easier to improve performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With