I'm working on an application that has a session timeout after 30 mins of inactivity. I have a new requirement to pop up a message asking users if they'd like to keep their session active, a couple mins before they're automatically logged out.
Right now the session is managed in what I think is a pretty unorthodox manner, and I need to try to work with what's already there. There's a service used by the App Module called context.service
(injected as a provider) that uses a setTimeout to determine when 30 mins of inactivity has expired.
Given that I need access to that countdown, I wanted to create a mirrored timeout that executes 2 mins earlier and fires the modal, asking the user if they want to keep their session open. After injecting NgbModal
into the ContextService
I receive a circular reference error which seems quite reasonable. It seems a little crazy to try to populate a modal on the DOM using a provider, but I'm not sure what a viable alternative is.
Here's the current state as it exists (with the circular reference error):
// ...
import { SessionExpirationWarning } from '../ponents/session-expiration-warning/session-expiration-warningponent';
// ....
constructor(
private _http: HttpClient,
private _injector: Injector,
private modalSvc: NgbModal
) {
// ...
}
// ...
setSessionTimeout() {
if (this.appConfig === null) { return; }
clearTimeout(this._timeoutId);
clearTimeout(this.timeoutWarning);
const sessionTimeOutConfig = this.appConfig.SessionTimeoutMinutes;
const SessionTimeoutMinutes = sessionTimeOutConfig === undefined ? 5 : sessionTimeOutConfig;
const sessionWarningMinutes = 2;
this._timeoutId = setTimeout(() => {
this.sessionExpired();
}, SessionTimeoutMinutes * (60 * 1000));
this.timeoutWarning = setTimeout(() => {
if (!this.warningIsActive) {
const timeOutWarningModal = this.modalSvc.open(SessionExpirationWarning);
timeOutWarningModal.result.then((modalResponse) => {
if (modalResponse === true) {
this.keepAlive(null);
}
});
}
}, sessionWarningMinutes * (60 * 1000));
}
The this.timeoutWarning
was my attempt at hacking together a solution.
I'm working on an application that has a session timeout after 30 mins of inactivity. I have a new requirement to pop up a message asking users if they'd like to keep their session active, a couple mins before they're automatically logged out.
Right now the session is managed in what I think is a pretty unorthodox manner, and I need to try to work with what's already there. There's a service used by the App Module called context.service
(injected as a provider) that uses a setTimeout to determine when 30 mins of inactivity has expired.
Given that I need access to that countdown, I wanted to create a mirrored timeout that executes 2 mins earlier and fires the modal, asking the user if they want to keep their session open. After injecting NgbModal
into the ContextService
I receive a circular reference error which seems quite reasonable. It seems a little crazy to try to populate a modal on the DOM using a provider, but I'm not sure what a viable alternative is.
Here's the current state as it exists (with the circular reference error):
// ...
import { SessionExpirationWarning } from '../ponents/session-expiration-warning/session-expiration-warning.ponent';
// ....
constructor(
private _http: HttpClient,
private _injector: Injector,
private modalSvc: NgbModal
) {
// ...
}
// ...
setSessionTimeout() {
if (this.appConfig === null) { return; }
clearTimeout(this._timeoutId);
clearTimeout(this.timeoutWarning);
const sessionTimeOutConfig = this.appConfig.SessionTimeoutMinutes;
const SessionTimeoutMinutes = sessionTimeOutConfig === undefined ? 5 : sessionTimeOutConfig;
const sessionWarningMinutes = 2;
this._timeoutId = setTimeout(() => {
this.sessionExpired();
}, SessionTimeoutMinutes * (60 * 1000));
this.timeoutWarning = setTimeout(() => {
if (!this.warningIsActive) {
const timeOutWarningModal = this.modalSvc.open(SessionExpirationWarning);
timeOutWarningModal.result.then((modalResponse) => {
if (modalResponse === true) {
this.keepAlive(null);
}
});
}
}, sessionWarningMinutes * (60 * 1000));
}
The this.timeoutWarning
was my attempt at hacking together a solution.
1 Answer
Reset to default 13What you could do is to have an Observable
that emits when the warning popup should be displayed:
import { timer } from 'rxjs/observable/timer';
// ...
public sessionWarningTimer$ = new Subject();
// ...
setSessionTimeout() {
// ...
timer(sessionWarningMinutes * 60 * 1000).subscribe(this.sessionWarningTimer$);
}
In a ponent (e.g. your AppComponent
) you could then subscribe to sessionWarningTimer$
:
private destroyed$ = new Subject();
ngOnInit() {
this
.contextService
.sessionWarningTimer$
.takeUntil(this.destroyed$)
.subscribe(() => this.displaySessionWarning());
}
ngOnDestroy() {
this.destroyed$.next();
}
displaySessionWarning() {
// your display code here
}
Like this, you can avoid any UI code in your service and rather focus on the warning logics.