I have a component A that can display an image:
<img *ngIf="manageImgService.isImg" (click)="manageImgService.hideImg()" src="...">
I also have a service (manageImgService) to manage when the image is displayed:
export class manageImgService{
isImg = false;
session?: Promise<'wasClosed'>;
showImg() {
if (this.isImg) return;
this.isOpen = true;
this.session = new Promise<1>((resolve) => {
//help
});
return this.session;
}
hideImg() {
if (!this.session) return;
//help
this.session = undefined;
this.isOpen = false;
}
}
I need this so that I can show the image from another component B and that component B is also informed when the image is closed again.
export class otherBComponent {
constructor(private manageImgService: ManageImgService){}
showImg(){
const res = this.manageImgService.showImg()
if (!res) return;
res.then((value) => console.log('image was hidden'));
}
}
How can I make this logic work?
Thank you very much!!
CodePudding user response:
If you are using Angular (and thus have RxJS baked in by default), this kind of behaviour can be achieved using a Subject
export class manageImgService {
isImageShownSubject: Subject<boolean> = new Subject<boolean>
}
export class otherBComponent {
constructor(private manageImgService: ManageImgService){}
ngOnInit() {
this.watchForImageChanges()
}
// How to notify a component of changes to the image display state
watchForImageChanges(){
this.manageImgService.isImageShownSubject
.asObservable()
.subscribe({
next: (isImageShown: boolean) => {
// Logic goes here
console.log(isImageShown)
}
})
}
// How to change the display state of the image from the component
showImgFromComponent(): void {
this.manageImgService.isImageShownSubject.next(true);
}
hideImgFromComponent(): void {
this.manageImgService.isImageShownSubject.next(false);
}
}
In practice a BehaviorSubject
may be preferable, as this will also allow you to emit a default value on creation of the subject (normal Subjects only emit a value the first time you call .next()
)
export class manageImgService {
isImageShownSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true) // default value goes here
// ...
}
If you only need the value of isImageShown
in the template, you can further simplify this through the use of the async
pipe. There would be no need to also have this value exposed in the component .ts
file, and so watchForImageChanges
can be omitted.
export class otherBComponent {
constructor(public manageImgService: ManageImgService) {}
}
<div>{{ manageImgService.isImageShownSubject | async }}</div>
// Will show true or false and update whenever the subject emits a new value