I've scenario where I am trying to add rows dynamically to a table using Ajax. I've following table structure:
<table class="user-table table" id="usersTable">
<thead>
<tr>
<th class="user-col user-name">Name</th>
<th class="user-col user-email">Email</th>
<th class="user-col user-status">Admin</th>
<th class="user-col user-i-col">Active</th>
<th class="user-col user-i-col">Actions</th>
</tr>
</thead>
</table>
Now I am trying to dynamically add/remove rows to/from table using JavaScript/jQuery. There are basically 2 different ways I am doing this:
- looping through JSON data, creating tbody, rows and cell and appending the tbody to target table using JavaScript OR
- using $(element).append(HTML) to append the HTML returned by Ajax call.
if I use JavaScript to create tbody, rows and data cells, NVDA correctly reads the added rows Ref: updateTableAsync . So if I add 3 rows to table this way, NVDA will read table with 4 rows and 5 columns, which is correct.
However, if I try to append the returned html directory into table using $.append or $.html, it does not identify the rows that were added dynamically. Ref: updateTableContentAsync
Here is the JSON that is returned:
{"users":[
{"name":"ABC","email":"ABC@mailcatch.com","admin":true, "active":true,"action":"Remove" },
{"name":"XYZ","email":"XYZ@mailcatch.com","admin":false, "active":false,"action":"Remove"},
{"name":"ASDF","email":"ASDF@mailcatch.com","admin":false, "active":true,"action":"Remove"}
]
}
(function(global, window, $) {
'use strict';
//Accessible Ajax Loading Test
var AALoadingTest = AALoadingTest || {};
AALoadingTest.AjaxUtil = (function() {
var makeDataCell = function(row, index, data ) {
var cell = row.insertCell(index);
var cellText = document.createTextNode(data)
cell.appendChild(cellText);
};
var setFocus = function(element, fallbackElement) {
var focusElement = document.getElementById(element);
if(typeof focusElement == 'undefined') {
focusElement = document.getElementById(fallbackElement);
}
window.setTimeout(function(){
window.console.log(focusElement);
focusElement.focus();
}, 100);
};
//Method : 1 Update table content by looping through json data using native Javascript
var updateTableAsync = function(url, targetTable, targetContainer, focusContainer, announce) {
//TODO: remove timeout when in prod, need while testing because locally changes are loading too fast
window.setTimeout( function() {
$.get(url, function(data){
var tempTargetTBody = document.getElementById(targetContainer);
var target = document.getElementById(targetTable);
var targetTBody = document.createElement('tbody');
targetTBody.innerHTML = '';
targetTBody.setAttribute('aria-live', tempTargetTBody.getAttribute('aria-live'));
// targetTBody.setAttribute('aria-atomic', tempTargetTBody.getAttribute('aria-live'));
tempTargetTBody.remove();
targetTBody.setAttribute('id',targetContainer);
$.each(data.users, function(key, value){
var row = targetTBody.insertRow(targetTBody.rows.length);
makeDataCell(row, 0, value.name);
makeDataCell(row, 1, value.email);
makeDataCell(row, 2, value.admin ? 'Yes': 'No');
makeDataCell(row, 3, value.active ? 'Yes': 'No');
makeDataCell(row, 4, value.action);
});
target.appendChild(targetTBody);
})
},5000);
};
//Method : 2 Update table content by inserting HTML element by looping through JSON returned into table
var updateTableHTMLAsync = function(url, targetTable, targetContainer, focusContainer, announce) {
//TODO: remove timeout when in prod, need while testing because locally changes are loading too fast
window.setTimeout( function() {
$.get(url, function(data){
var targetElement = $('#'+targetContainer);
targetElement.remove();
targetElement = $('<tbody></tbody>').attr({'aria-live': 'polite', 'id': targetContainer});
$.each(data.users, function(key, value) {
window.setTimeout(function() {
var row = $("<tr> </tr>");
targetElement.append(row);
row.append($("<td></td>").text(value.name));
row.append($("<td></td>").text(value.email));
row.append($("<td></td>").text((value.admin ? 'Yes': 'No')));
row.append($("<td></td>").text((value.active ? 'Yes': 'No')));
row.append($("<td></td>").text(value.action));
},100);
});
$("#"+targetTable).append(targetElement);
})
},5000);
};
//Method : 3 Update table content by inserting HTML returned into table
var updateTableContentAsync = function(url, targetTable, targetContainer, focusContainer, announce) {
//TODO: remove timeout when in prod, need while testing because locally changes are loading too fast
window.setTimeout( function() {
$.get(url, function(data){
var targetElement = $('#'+targetContainer);
targetElement.remove();
targetElement = $('<tbody></tbody>').attr({/*'aria-live': 'polite',*/ 'id': targetContainer});
$("#"+targetTable).append(targetElement);
targetElement.append($(data));
})
},5000);
};
return {
updateTableAsync: updateTableAsync,
updateTableHTMLAsync: updateTableHTMLAsync,
updateTableContentAsync: updateTableContentAsync,
removeLoader: removeLoader,
loader: loader
};
})();
$("#asyncHTML").on("click", function(e){
e.stopPropagation();
AALoadingTest.AjaxUtil.updateTableHTMLAsync(
$(this).attr('data-resource'),
$(this).attr('data-target-table'),
$(this).attr('data-target-element'),
$(this).attr('data-focus-element'),
true
);
return false;
});
$("#asyncJSON").on("click", function(e){
e.stopPropagation();
AALoadingTest.AjaxUtil.updateTableAsync(
$(this).attr('data-resource'),
$(this).attr('data-target-table'),
$(this).attr('data-target-element'),
$(this).attr('data-focus-element'),
true
);
return false;
});
$("#asyncHTMLContent").on("click", function(e){
e.stopPropagation();
AALoadingTest.AjaxUtil.updateTableContentAsync(
$(this).attr('href'),
$(this).attr('data-target-table'),
$(this).attr('data-target-element'),
$(this).attr('data-focus-element'),
true
);
return false;
});
})(this, window,jQuery);
<link href="http://ift.tt/1mDOveJ" rel="stylesheet"/>
<script src="http://ift.tt/1qRgvOJ"></script>
<script src="http://ift.tt/1h4yM0u"></script>
<main>
<div class="container">
<div class="container-fluid">
<h1>Dynamic Tables</h1>
<p> Load JSON using Ajax get, use JavaScript to create tbody, rows and data cell and append the tbody to table using appendChild</p>
<br>
<a class="btn btn-primary async" id="asyncJSON" data-target-table="usersTableJSON"
role="button" data-target-element="userTableBodyJSON" data-focus-element="asyncContentJSON"
href="javascript:;" data-resource="data/users.json">
Load Users <span class="sr-only">Load json Data</span>
</a>
<br>
<br>
<div class="panel" id="asyncContentJSON">
<table class="user-table table" id="usersTableJSON">
<thead>
<tr>
<th class="user-col user-name">Name</th>
<th class="user-col user-email">Email</th>
<th class="user-col user-status">Admin</th>
<th class="user-col user-i-col">Active</th>
<th class="user-col user-i-col">Actions</th>
</tr>
</thead>
<tbody id="userTableBodyJSON" aria-live="polite"></tbody>
</table>
</div>
<br>
<p> Load JSON using Ajax get, use jQuery to create tbody, rows and data cell and append the tbody to table using $.append</p>
<br>
<a class="btn btn-primary async2" id="asyncHTML"
role="button" data-target-element="userTableBodyHTML" data-target-table="usersTableHTML" data-focus-element="asyncContentHTML"
href="data/rows.html" data-resource="data/users.json">
Load Users<span class="sr-only">Load HTML Data</span>
</a>
<br>
<br>
<div class="panel" id="asyncContentHTML">
<table class="user-table table" id="usersTableHTML">
<thead>
<tr>
<th class="user-col user-name">Name</th>
<th class="user-col user-email">Email</th>
<th class="user-col user-status">Admin</th>
<th class="user-col user-i-col">Active</th>
<th class="user-col user-i-col">Actions</th>
</tr>
</thead>
<tbody id="userTableBodyHTML" aria-live="polite"></tbody>
</table>
</div>
<br>
<p> Load JSON using Ajax get, use JavaScript to create tbody, rows and data cell and append the tbody to table using $.html</p>
<br>
<a class="btn btn-primary async2" id="asyncHTMLContent"
role="button" data-target-element="userTableBodyHTMLContent" data-target-table="usersTableHTMLContent" data-focus-element="asyncContentHTMLContent"
href="data/rows.html" data-resource="">
Load Users<span class="sr-only">Load HTML View</span>
</a>
<br>
<br>
<div class="panel" id="asyncContentHTMLContent">
<table class="user-table table" id="usersTableHTMLContent">
<thead>
<tr>
<th class="user-col user-name">Name</th>
<th class="user-col user-email">Email</th>
<th class="user-col user-status">Admin</th>
<th class="user-col user-i-col">Active</th>
<th class="user-col user-i-col">Actions</th>
</tr>
</thead>
<tbody id="userTableBodyHTMLContent" aria-live="polite"></tbody>
</table>
</div>
</div>
</div>
<div id="overlay" class="hidden">
<span class="visuallyHidden" id="loadingMessage" role="status" aria-hidden="true"></span>
</div>
</main>
One thing that I suspect here is: when I manually add rows one by one, NVDA is aware of individual DOM change, however, when I update the innerHTML all it know is "one update in DOM". Please let me know if someone has faced similar issue and how you fixed that.
Thanks
Aucun commentaire:
Enregistrer un commentaire