ㅇ
부트스트랩을 이용해서 프로그램을 사용중인데, 모달창이 닫힐때 항상 아래의 오류가 난다. 이 부분에 대한 해결책이 궁금하다.
list_mat.php:1 Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will also prevent focus. For more details, see the aria-hidden section of the WAI-ARIA specification at https://w3c.github.io/aria/#aria-hidden.
Element with focus: button
Ancestor with aria-hidden: <div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel" style="display: block; padding-left: 0px;" aria-hidden="true">…</div>
이제 인공지능의 능력을 이용해서 해결해 보는 과정을 담아봅니다.
질문하기 : )
이미 CDN은 선언되어있고, 해당 코드를 공유한다.
- 자바스크립트
$(document).ready(function(){
// 검색 버튼 클릭 시 폼 제출
$("#searchBtn").click(function(){
$("#board_form").submit();
});
// 테이블 행 클릭 시 상세 모달 열기
$("#myTable tbody tr").on('click', function(){
var steel_item = $(this).data('steel-item');
var spec = $(this).data('spec');
// AJAX 요청으로 상세 내역 가져오기
$.ajax({
url: 'fetch_detail.php',
type: 'POST',
data: { steel_item: steel_item, spec: spec },
dataType: 'json',
success: function(response){
if(response.error){
alert('오류: ' + response.error);
} else {
var tbody = $('#detailTable tbody');
tbody.empty();
$.each(response, function(index, row){
var tr = '<tr>' +
'<td class="text-center">' + row.inoutdate + '</td>' +
'<td class="text-center">' + row.item_code + '</td>' +
'<td class="text-center">' + row.spec + '</td>' +
'<td class="text-center">' + (row.total_in !== '' ? numberWithCommas(row.total_in) : '') + '</td>' +
'<td class="text-center">' + (row.total_out !== '' ? numberWithCommas(row.total_out) : '') + '</td>' +
'<td class="text-center">' + (row.stock !== '' ? numberWithCommas(row.stock) : '') + '</td>' +
'<td class="text-center">' + row.workplacename + '</td>' +
'<td class="text-center">' + row.secondord + '</td>' +
'<td class="text-center">' + row.supplier + '</td>' +
'<td class="text-center">' + row.company + '</td>' +
'</tr>';
tbody.append(tr);
});
// 모달 열기
var detailModal = new bootstrap.Modal(document.getElementById('detailModal'));
detailModal.show();
}
},
error: function(xhr, status, error){
console.error(xhr);
alert('데이터를 불러오는 중 오류가 발생했습니다.');
}
});
});
function numberWithCommas(x) {
if(x === '' || x === null) return '';
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
});
```````````````````````````
- html 코드
<!-- 8. 모달 창 (재고 상세 내역) -->
<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-full">
<div class="modal-content table-container">
<div class="modal-header">
<h5 id="detailModalLabel" class="modal-title">재고 상세 내역</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="닫기"></button>
</div>
<div class="modal-body">
<table class="table table-hover" id="detailTable">
<thead class="table-primary">
<tr>
<th class="text-center" >입출고일자</th>
<th class="text-center" >품목코드</th>
<th class="text-center" >규격</th>
<th class="text-center" >입고수량</th>
<th class="text-center" >출고수량</th>
<th class="text-center" >재고</th>
<th class="text-center" >현장명</th>
<th class="text-center" >발주처</th>
<th class="text-center" >공급처</th>
<th class="text-center" >사급</th>
</tr>
</thead>
<tbody>
<!-- AJAX로 로드된 데이터 -->
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
<button type="button" class="btn btn-success downloadExcel">엑셀 다운로드</button>
</div>
</div>
</div>
</div>
클로드에게 물어본 결과를 공유해 봅니다.
이 오류는 모달이 닫힐 때 접근성(accessibility) 관련 문제가 발생하는 것입니다. 주요 원인은 모달이 닫힐 때 `aria-hidden="true"`가 설정되어 있는데, 내부에 포커스 가능한 요소(버튼 등)가 있어서 발생하는 충돌입니다.
이 문제를 해결하기 위해 다음과 같은 방법들을 시도해볼 수 있습니다:
1. 모달 설정을 수정하는 방법:
```javascript
$(document).ready(function(){
// 모달 인스턴스 생성
const detailModal = new bootstrap.Modal(document.getElementById('detailModal'), {
backdrop: 'static', // 배경 클릭으로 닫히지 않도록 설정
keyboard: true // ESC로 닫을 수 있도록 설정
});
// 모달이 완전히 닫힌 후 포커스 처리
$('#detailModal').on('hidden.bs.modal', function () {
// 포커스를 다른 요소로 이동
document.body.focus();
});
```
2. HTML 구조 수정:
```html
<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel">
<!-- aria-hidden 속성 제거 -->
<div class="modal-dialog modal-full" role="document">
<div class="modal-content table-container">
<!-- 나머지 코드는 동일 -->
</div>
</div>
</div>
```
3. 모달 닫기 버튼의 처리를 수정:
```javascript
// 모달 닫기 버튼 클릭 이벤트
$('.btn-close, .btn-secondary').on('click', function() {
// 포커스를 해제하고 모달 닫기
$(this).blur();
detailModal.hide();
});
```
4. CSS를 통한 해결방법:
```css
.modal.fade {
&[aria-hidden="true"] {
pointer-events: none;
button, [tabindex] {
pointer-events: none;
tabindex: -1;
}
}
}
```
이러한 방법들을 조합하여 사용하면 오류를 해결할 수 있습니다. 가장 추천하는 방법은 1번과 2번을 함께 적용하는 것입니다. 이렇게 하면:
1. 모달이 닫힐 때 포커스가 적절히 처리됩니다.
2. 접근성 관련 속성들이 올바르게 설정됩니다.
3. 스크린 리더 사용자들에게도 더 나은 경험을 제공할 수 있습니다.
추가로, Bootstrap 5.x 버전을 사용중이라면, 최신 버전으로 업데이트하는 것도 이 문제를 해결하는데 도움이 될 수 있습니다.
$(document).ready(function(){
// 검색 버튼 클릭 시 폼 제출
$("#searchBtn").click(function(){
$("#board_form").submit();
});
// 테이블 행 클릭 시 상세 모달 열기
$("#myTable tbody tr").on('click', function(){
var steel_item = $(this).data('steel-item');
var spec = $(this).data('spec');
// AJAX 요청으로 상세 내역 가져오기
$.ajax({
url: 'fetch_detail.php',
type: 'POST',
data: { steel_item: steel_item, spec: spec },
dataType: 'json',
success: function(response){
if(response.error){
alert('오류: ' + response.error);
} else {
var tbody = $('#detailTable tbody');
tbody.empty();
$.each(response, function(index, row){
var tr = '<tr>' +
'<td class="text-center">' + row.inoutdate + '</td>' +
'<td class="text-center">' + row.item_code + '</td>' +
'<td class="text-center">' + row.spec + '</td>' +
'<td class="text-center">' + (row.total_in !== '' ? numberWithCommas(row.total_in) : '') + '</td>' +
'<td class="text-center">' + (row.total_out !== '' ? numberWithCommas(row.total_out) : '') + '</td>' +
'<td class="text-center">' + (row.stock !== '' ? numberWithCommas(row.stock) : '') + '</td>' +
'<td class="text-center">' + row.workplacename + '</td>' +
'<td class="text-center">' + row.secondord + '</td>' +
'<td class="text-center">' + row.supplier + '</td>' +
'<td class="text-center">' + row.company + '</td>' +
'</tr>';
tbody.append(tr);
});
// 모달 열기
var detailModal = new bootstrap.Modal(document.getElementById('detailModal'));
detailModal.show();
// 모달이 완전히 닫힌 후 포커스 처리
$('#detailModal').on('hidden.bs.modal', function () {
// 포커스를 다른 요소로 이동
document.body.focus();
});
// 모달 닫기 버튼 클릭 이벤트
$('.btn-close').on('click', function() {
// 포커스를 해제하고 모달 닫기
$(this).blur();
detailModal.hide();
});
}
},
error: function(xhr, status, error){
console.error(xhr);
alert('데이터를 불러오는 중 오류가 발생했습니다.');
}
});
});
function numberWithCommas(x) {
if(x === '' || x === null) return '';
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
});
위의 코드로 실행하니 실제 오류가 없어졌다.
정말 많은 고민을 했던 부분인데... 해소되서 너무 좋다.
chatGPT에서는 사실 해결되지 않는 것인데, 클로드가 더 코드지향적인가?라는 생각을 잠시 하게 되네요~
더 코드개발하는 사람에게 적합한 것이 클로드가 아닌가 싶은 시점입니다.
아직 유료결재를 안해서... 하루 무료량만 사용하고 있지만, 조만간 결재를 해야할 것 같아요^^
실제 모달창이 뜨고 오류가 없는 것을 확인했습니다.