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 { 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
],
In the formsDemo.ts file, add the following method:{path: 'forms', component: FormsDemo, canDeactivate: [CanDeactivateGuard]},
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)
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
})
What can I do to have the confirmDialog to display in the Ultima template when invoked in that way?
Thanks,