1
votes

Dialog is opening multiple times because subscription is called twice/multiple times after ngrx state mutation.

  1. Tried using takeUntil(loadingComplete) with loadingComplete = new BehaviorSubject(false) but doesnt works with my logic. Because atleast once this subscription should be called after job states is "COMPLETED".

  2. Tried using take(1) since i am polling for getting progress status can't be fetched after first subscription on using take 1. So added isCompleteDialogOpened flag to control multiple subscription dialog to open once. But each time subscription is called isCompleteDialogOpened remains !false in

    if(uploadStatus.jobStatus === 'COMPLETED' && !this.isCompleteDialogOpened)
    

even after i set it to true on first subscription in openUploadCompleteDialog() method call isCompleteDialogOpened is false on second subscribe so dialog is opened multiple times.

 isCompleteDialogOpened = false;   // -->Init as false

 ngOnInit() {
            this.pollUploadStatus(); // --> Oninit call for subscription method
        }

 pollUploadStatus() { // --> uploadStore ngrx store when selectCurrentJob mutates this is subscribed
        this.uploadStore.select(selectCurrentJob)
            .pipe(filter(uploadJob => !!uploadJob && !!uploadJob.jobStatus))
            .subscribe((uploadJob) => { // --> Subscription called multiple times
                const uploadStatus = uploadJob.jobStatus;


                  // --> this.isCompleteDialogOpened remains false even if i set true when
                  // --> the dialog is opened on first subscription How to maintain the state 
                  // --> of 'isCompleteDialogOpened'  on each subscription so that when the second
                 // -->  subscription made it is set true and condition fails


                if (uploadStatus.jobStatus === 'COMPLETED' && !this.isCompleteDialogOpened) {
                    this.openUploadCompleteDialog(); // --> upload dialog box is called twice
                }             
    }


openUploadCompleteDialog(): void {

    this.isCompleteDialogOpened = true; // --> set true after dialog open on subscription

    const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
        data: ....
    });
    dialogRef.afterClosed().subscribe(result => {
        const message = this.translate
            .instant('upload-success');
        this.openUploadSnackBar(true, message);
        this.router.navigateByUrl('car/add-update/car-history');
    });
}

 ngOnDestroy() {
        this.uploadStore.dispatch(stopPolling({}));
        this.destroy$.next();
        this.destroy$.complete();
    }

Might be duplicate of How to stop a subscription after the response to a service/store has a certain argument/value but takeUntil doesn't works for my logic

Is there any way to make the dialog box open once after the state change to "COMPLETED" based on flag, If it is flag how to maintain state on each subscribe or something. Any help would be great.

Using Angular8, Rxjs 6.5.2.

2
My guess, would be that some state change is happening (since you are subscribing to it). Have you thought about using a DistinctUntilChanged on uploadJob.jobStatus. Here is an example: dpaste.com/094JFZ8 this way, your subscription should only be refreshed when this value in state changescrooksey

2 Answers

1
votes

Dunno why select fires too often, but here

 pollUploadStatus() { // --> uploadStore ngrx store when selectCurrentJob mutates this is subscribed
        this.uploadStore.select(selectCurrentJob)
            .pipe(filter(uploadJob => !!uploadJob && !!uploadJob.jobStatus))

adding distinctUntilChanged (probably with a custom matcher, since the stream contains objects, not primitives) to the pipe, after the filter, should solve the problem.

0
votes

Just for Info : When i navigate to some other tab return back this subscription remained unsubscribed that's the issue. DistinctUntilChanged helped me to find the main issue by printing logs and remove those flags and made my code clean.

private destroy$ = new Subject<void>();

pollUploadStatus() {
    this.uploadStore.select(selectCurrentJob)
        .pipe(filter(uploadJob => !!uploadJob && !!uploadJob.jobStatus),
        distinctUntilChanged((prev, curr) =>
            prev.jobStatus.percentComplete === curr.jobStatus.percentComplete),
            takeUntil(this.destroy$))
        .subscribe((uploadJob) => {
            const uploadStatus = uploadJob.jobStatus;
            if (uploadStatus.jobStatus === 'COMPLETED') {
                this.openUploadCompleteDialog(); --> this.router.navigateByUrl('car/add-update/car-history');
            }
        });
}

ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
}