I'm learning Angular and I have a pretty simple question : I have an Observable that I use to track if a side menu is closed or opened. I get to have my Observable to start with 'true' as a value, but I really don't get how I can swap it so it does this logic : value = !value
Here's my service :
import { Injectable } from '@angular/core';
import { Observable, startWith } from "rxjs";
@Injectable({
providedIn: 'root'
})
export class SideMenuService {
private open$ = new Observable<boolean>().pipe(
startWith<boolean>(true)
);
constructor() { }
getOpen() {
return this.open$;
}
swapOpen() {
// Here I want to make open$ to be false
}
}
And here's my Typescript file :
import { Component, OnInit } from '@angular/core';
import { SideMenuService } from "../../../services/side-menu/side-menu.service";
@Component({
selector: 'side-menu',
templateUrl: './side-menu.component.html',
styleUrls: ['./side-menu.component.css']
})
export class SideMenuComponent implements OnInit {
public open!: boolean;
constructor(
private sideMenuService: SideMenuService
) { }
ngOnInit(): void {
this.sideMenuService.getOpen()
.subscribe(result => this.open = result);
}
swtichTriggered(): void {
this.sideMenuService.swapOpen();
}
}
How can I toggle the value properly in the swapOpen() function?
CodePudding user response:
Some RxJS operator magic via scan
(On mobile so forgive the formatting)
toggle$ = new Subject<void>()
// either subscribe or better yet use async pipe in component
isOpen$ = toggle$.pipe(
// start with true then switch on toggle emission
scan((acc, _) => !acc, true)
)
toggle$.next() // triggers isOpen$ i.e. use in swapOpen
// don’t forget to clean up subscriptions
CodePudding user response:
You can create a BehaviourSubject and toggle its value whenever the sidebar opens or closes
import { Injectable } from '@angular/core';
import { Observable, startWith } from "rxjs";
@Injectable({
providedIn: 'root'
})
export class SideMenuService {
private open$ = new BehaviourSubject<boolean>(true);
constructor() { }
getOpen() {
return this.open$;
}
swapOpen(value: boolean) {
this.open$.next(value);
}
}
In your component where you are looking at the component
import { Component, OnInit } from '@angular/core';
import { SideMenuService } from "../../../services/side-menu/side-menu.service";
@Component({
selector: 'side-menu',
templateUrl: './side-menu.component.html',
styleUrls: ['./side-menu.component.css']
})
export class SideMenuComponent implements OnInit {
public open!: boolean;
constructor(
private sideMenuService: SideMenuService
) { }
ngOnInit(): void {
this.sideMenuService.getOpen()
.subscribe(result => this.open = result);
}
swtichTriggered(): void {
this.sideMenuService.swapOpen(!this.open);
}
}
One of the benefits of using a Subject
over an Observable
would be that it is multicast so only a single instance of the Subject
will be used to pass value to its Observers
.
The same behavior can be achieved in the Observable
by using share
operator which basically uses a Subject
underneath its implementation.