kevcjones / ngx-simple-modal

A simple unopinionated framework to implement simple modal based behaviour in angular (v2+) projects.
MIT License
52 stars 27 forks source link

Double call of onClosing callback for a modal that is subscribed #80

Open Eregrith opened 2 years ago

Eregrith commented 2 years ago

I'm trying to troubleshoot a problem on my app where it appears to me that the closing callback is called twice for only one closing of my modal.

I'm calling the modal like this:

this.simpleModalService.addModal(
      MyComponent,
      data,
      {
        closeOnClickOutside: false,
        wrapperClass: 'fullscreen-modal'
      }
    ).subscribe((result:  MyResult) => {
      console.log("my result:", result);
    });

[...]
export class MyComponent extends SimpleModalComponent<MyData, MyResult> {

  public mapDataObject(data: AcceptPhotoCaptureData) {
    [... some data mapping]
    console.log("%c Subscribing to back button in modal page", 'background-color: black; color: red; font-weight: bold');
    this.backButtonSub = this.platform.backButton.subscribe(() => {
      console.log("back button activated for modal page");
      this.result = { Accepted: false, Comment: this.comment };
      this.close();
    });
  }

  onClosing(callback: (component: SimpleModalComponent<any, any>) => Promise<any>): void {
    super.onClosing((component) => {
      console.groupCollapsed("onClosing of MyComponent called. Callback:", callback);
      console.trace();
      console.groupEnd();
      if (this.backButtonSub) {
        console.log("%c Unsubscribing from back button in modal page", 'background-color: black; color: green; font-weight: bold');
        this.backButtonSub.unsubscribe();
      }
      return callback(component);
    });
  }
}

When I hit the back button of my device, the back button subscriber is triggered and the modal's close() method is called. The callback of onClosing() is called here and the unsubscribe happens. Then the subscriber of the addModal method's observable is triggered and the console shows "my result: " and the result. Then, because Observable's complete() calls unsubscribe(), the callback of onClosing() is called again which should not happen twice.

Here is the stack trace of the first call of the callback: image

The first (anonymous) is the caller to console.trace() which is the callback passed to the onClosing method, which is called by close() in class SimpleModalComponent which is called by another (anonymous): the backbutton callback passed to this.platform.backButton.subscribe

The second call stack trace to the callback: image (I renamed the function to customClosingCallback in-between)

The first customClosingCallback is the same caller of console.trace() which is the callback passed to the onClosing method. It's called by close() which is again called by an (anonymous) method, but this time it's the return callback of setupObserver:

    setupObserver() {
        return rxjs__WEBPACK_IMPORTED_MODULE_3__["Observable"].create(observer => {
            this.observer = observer;
            // called if observable is unsubscribed to
            return () => {
                this.close();
            };
        });
    }

And this call comes from the unsubscribe() chain triggered by the call to complete() in the close() method of class SimpleModal, identified by the last (anonymous) line in the above capture:

    close() {
        return this.closerCallback(this).then(v => {
            if (this.observer) {
                this.observer.next(this.result);
                this.observer.complete();
            }
            return v;
        });
    }