Home > Software engineering >  Promise resolves when a method is called
Promise resolves when a method is called

Time:12-26

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
  • Related