ConfirmDialog with ChangeDetectionStrategy.OnPush

Forum rules
Please note that response time for technical support is within 3-5 business days.
Post Reply
NGAllie
Posts: 24
Joined: 21 Sep 2016, 20:36

07 May 2017, 21:22

Hi,

I'm currently integrating NGRX in our app based on Ultima and I'm facing an issue with the PrimeNG ConfirmDialog/ConfirmationService combo that we use to display the confirmation message for the canDeactivate guard when appropriate. Everything works fine until I set a component protected by the canDeactivate guard to use ChangeDetectionStrategy.OnPush. When I do this and navigate away from a protected component having changes , the overlay appears but not the confirmation dialog. I can't click on anything because of the overlay, but if I hit the tab key I can see the focus moving to menu items, then to components in the form and at some point it brings the confirmation dialog into view.

At first I thought that I needed to trigger change detection to get the confirm dialog to display, so I tried different combinations using ngZon.run() but it didn't help. I then saw an issue raised on github for a similar problem but with the dialog component and without reference to the change detection strategy being used: https://github.com/primefaces/primeng/issues/2720 . As reported in this issue, I can also see by inspecting the DOM that the dialog has style="display: none when not visible and that it turns to display:block when the dialog shows up after tabbing to it.

You can replicate this issue in the Ultima template project (upgraded to angular 4.0.0 and PrimeNG 4.0.0) by adding a protected guard to the FormsDemo component. Here are the repro steps:

Create a can-deactivate-guard.service.ts file in the app folder and insert the following code:

Code: Select all

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';

export interface CanComponentDeactivate {
    canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {

    canDeactivate(component: CanComponentDeactivate) {
        return component.canDeactivate ? component.canDeactivate() : true;
    }
}
Import this service and PrimeNG ConfirmationService in the app.module file and add both service to the providers section of AppModule
import { ConfirmationService } from 'primeng/primeng';
import { CanDeactivateGuard } from './can-deactivate-guard.service';

Code: Select all

    providers: [
        {provide: LocationStrategy, useClass: HashLocationStrategy},
        CarService,CountryService,EventService,NodeService, ConfirmationService, CanDeactivateGuard
    ],
Import CanDeactivateGuard in the routes.ts file and guard the route to the formsdemo component
{path: 'forms', component: FormsDemo, canDeactivate: [CanDeactivateGuard]},
In the formsDemo.ts file, add the following method:

Code: Select all

    public canDeactivate(): Promise<boolean> | boolean {
	// always ask for debugging 
        return new Promise((resolve, reject) => {
            this.confirmationService.confirm({
                message: 'Discard changes to course?',
                accept: () => {
                    // Actual logic to perform a confirmation
                    resolve(true);
                },
                reject: () => {
                    // Actual logic to perform a no
                    resolve(false);
                }
            });
        });
    }

Import PrimeNG ConfirmationService in that component and inject it in the constructor:

Code: Select all

    constructor(private countryService: CountryService, private confirmationService: ConfirmationService)
Do ng serve and go to the forms demo page. When you navigate away the confirmation dialog should work as expected.

Then go back to the formsDemo.ts file and import ChangeDetectionStrategy and set changeDetection to OnPush:

Code: Select all

import { ChangeDetectionStrategy } from '@angular/core';

@Component({
    templateUrl: './formsdemo.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
ng serve and try the formsDemo component again. When you navigate away, you should now see the overlay but not the confirm dialog. If you hit tab, you will see the focus moving to menu items and the then form controls and finally you will get the confirmation dialog.

What can I do to have the confirmDialog to display in the Ultima template when invoked in that way?

Thanks,

User avatar
DarthMaul
Posts: 582
Joined: 23 Nov 2015, 21:20

11 May 2017, 14:05

Hi,

I will review this and get back to you.

Regards

NGAllie
Posts: 24
Joined: 21 Sep 2016, 20:36

12 May 2017, 00:21

Thanks DarthMaul,

I finally got it to work by injecting (private cd: ChangeDetectorRef) in the constructor and calling markForCheck() just before calling the confirmation service.

My revised CanDeactivate method:

Code: Select all

    public canDeactivate(): Promise<boolean> | boolean {

        // Always ask for debugging purposes
        return new Promise((resolve, reject) => {
            this.cd.markForCheck();
            this.confirmationService.confirm({
                message: 'Discard changes to course?',
                accept: () => {
                    // Actual logic to perform a confirmation
                    resolve(true);
                },
                reject: () => {
                    // Actual logic to perform a no
                    resolve(false);
                }
            });
        });
    } 
The confirmation dialog shows up as expected when used that way with changeDetectionStrategy.OnPush

Regards,

User avatar
DarthMaul
Posts: 582
Joined: 23 Nov 2015, 21:20

15 May 2017, 09:00

Hi,

Great to hear that.

Regards

Post Reply

Return to “Ultima - PrimeNG”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 13 guests