Search code examples
angularangular2-servicesswitchmapcombinelatestangular-resolver

Invoke modal inside SwitchMap in angular2 resolver


I have a requirement of displaying modal popup based on warning message inside angular resolver. I am making a service call to API and using combineLatest and SwitchMap returning multiple responses. I need to display modal popup based on API service response result and redirect to different route if that modal pop up shown and clicked. Otherwise, resolver can return mutiple responses. I have tried below code and when debugging, my modal is not being hit and skipped and returns the responses. what changes to be done in below code so that when any warning message available, modal could be shown up and route to different page? I have searched other questions and could not see relevant like this.

@Injectable()
export class TestResolver implements Resolve<{ aResponse: AResponse, bRepsonse: BResponse, cRepsonse: CResponse[] }> {

  constructor(private testservice: TestService, private modalService: ModalService, private router: Router) { }

  resolve(route: ActivatedRouteSnapshot)
    : Observable<{ aRes: AResponse, bRes: BRepsonse, cRes: CRepsonse[] }> {

    const a = this.testservice.getAResponse()
    const b = this.testservice.getBResponse()
    const c = this.testservice.getCResponse()

    return combineLatest(a, b, c).pipe(

      switchMap(([aRes, bRes, cRes]) => {
        const aData = aRes.someData
        const bData = bRes.someData
        const cData = cRes.someData

        const warningMessage = GetWarningMessage(aRes)
        if (warningMessage) {
          this.modalService.create<ModalComponent>(ModalComponent, {
            message: warningMessage,
            modalLabel: '',
            closeLabel: 'Close',
            close: () => this.router.navigate(['..']),
          })
        }
        return of({ aRes: aData, bRes: bData, cRes: cData})
      })
    )
  }
}

Modal.Component.ts

import { Component, Input } from '@angular/core'

@Component({
  template: `
    <div class="brick brick--vertical">
      <div class="brick__wrapper">
        <div class="brick__content">
          <h2 id="modal_label" [innerHTML]="modalLabel"></h2>
          <div class="message-content" [innerHTML]="message"></div>
          <div class="buttons">
            <div class="buttons__group">
              <button df-button="primary" id ="close_button" (click)="close()">{{ closeLabel }}</button>
            </div>
          </div>
        </div>
      </div>
    </div>`
})

export class ModalComponent {
  @Input() message = ''
  @Input() closeLabel = 'Close'
  @Input() modalLabel = ''


  close: () => any
}

Solution

  • If you're using ngb-bootstrap, you can return a observable from the result (ngb-pop return a promise.

    In stackblitz I put a simple example based on the most simple example of the popUp

    You has a function that return an observable. See that we using catchError because in ngb-popup the "close" or "esc" or "click outside" fall in promise error

    open(content) {
        this.modalRef=this.modalService.open(content, {ariaLabelledBy: 'modal-basic-title'})
    
        return from(this.modalRef.result).pipe(catchError((error) => {
            return of(this.getDismissReason(error))
          }));
    }
    

    Then you can subscribe to the function, e.g.

    click(content)
      {
        this.open(content).subscribe(res=>{
          console.log(res)
        })
      }
    

    Or in you case, some like

    switchMap(([aRes, bRes, cRes]) => {
       ....
       return this.open(content).map(res=>{
          //here you has the response of the popUp
          if (res=="Save Click")
          {
             ......
             return true
          }
          return false
       })
    }