I'm figuring out to make my existing modal popup compliant with ADA, so as the focus of the keyboard Tab remain under this modal container made used of user defined handleTabKeyFocus()
. But querySelector
selector always returns null with querySelectorAll
results in
ERROR TypeError: Cannot read property 'querySelectorAll' of null
<!-- Modal Popup for Candidate Information -->
<ng-template #candidateInfoTemplate>
<div class="modal-header" id="xc">
<h5 class="modal-title float-left"> <b>Candidate Information </b></h5>
<button type="button" class="close pull-right" aria-label="Close" (click)="closeModalWithFocus(candidateDetailTCInfo.examUserID)" title="CLOSE">
<span aria-hidden="true">x</span>
</button>
</div>
<!-- Modal body -->
<div class="modal-body backgroundColorWhite" id="modalBody">
<div class="row mb-1 backgroundColorgray" *ngIf="!disableColumn">
<div class="col-sm-5">
Candidate Id
</div>
<div class="col-sm-1">
:
</div>
<div class="col-sm-6">
{{candidateDetailTCInfo?.loginName}}
</div>
</div>
<div class="clearfix"></div>
<!-- Modal Footer-->
<div style="text-align:center" ModFocus>
<button title="{{ResourceKeys.sbclose}}" type="button" class="btn btn-light btn_mng1 mr5" aria-label="Close" (click)="closeModalWithFocus(candidateDetailTCInfo.examUserID)">
{{ResourceKeys.sbclose}}
</button>
</div>
</div>
</ng-template>
@HostListener('document:keydown', ['$event'])
handleTabKeyFocus(e) {
if (e.keyCode === 9) {
let focusable = document.querySelector('#candidateInfoTemplate').querySelectorAll('input,button,select,textarea,a,[tabindex]:not([tabindex="-1"])');
// It returns null
if (focusable.length) {
let first = focusable[0];
let last = focusable[focusable.length - 1];
let shift = e.shiftKey;
if (shift) {
if (e.target === first) { // shift-tab pressed on first input in dialog
(last as HTMLElement).focus();
e.preventDefault();
}
} else {
if (e.target === last) { // tab pressed on last input in dialog
(first as HTMLElement).focus();
e.preventDefault();
}
}
}
}
}
<div (click)="opencandidateDetailsModal(candidateInfoTemplate, detail)" >
<a href="#" onclick="return false;" [attr.id]="'candidateNameFocus_' + detail.examUserID" > {{detail.candidateName}} </a>
</div>
opencandidateDetailsModal(template: TemplateRef<any>, candObj: any) {
try {
this.getCandidateDetailTestInfo(candObj);
this.modalRef = this.modalService.show(template, this.modalPopupconfig);
} catch (error) {
console.log('Method: opencandidateDetailsModal', error);
}
}
closeModalWithFocus(examUserID: any) {
try {
this.modalRef.hide();
const candidateFocusElement: HTMLElement = (<HTMLElement>document.getElementById('candidateNameFocus_' + examUserID));
if (candidateFocusElement !== null) {
candidateFocusElement?.focus();
}
const previousActiveElement = document.activeElement;
if (document.body.contains(previousActiveElement)) {
(previousActiveElement as HTMLElement)?.focus();
}
} catch (error) {
console.log('Method: closeModalWithFocus', error);
}
}
Inbuilt ngx-bootstrap
uses ng-template with the given id as candidateInfoTemplate
let focusable = document.querySelector('#candidateInfoTemplate').querySelectorAll('input,button,select,textarea,a,[tabindex]:not([tabindex="-1"])');
Before opening the modal popup throws an error when a keyboard event occurs
Cannot read property 'querySelectorAll' of null
How do we retain focus with in the modal popup with ngx-bootstrap
?...
#candidateInfoTemplate
is not an id, it is a reference to <ng-template>
. You can access that using @ViewChild decorator.
But for above issue, you can fix that by adding extra <div>
inside <ng-template>
tag with an id
<ng-template #candidateInfoTemplate>
<div id="candidateInfoTemplate">
...
</div>
</ng-template>