Adding Aria-labels to Angular pagination grid to make it more accessible
Asked Answered
W

2

6

In this plunker example I borrowd from this thread, there is an awesome example of how to create a pagination grid using AngularJs. (My question differs a bit from this similar question.)

In one of our projects, we have a quite similar solution, but in order to get some help, I will use the code from the plunker I mentioned above.

My goal: I'd like to make the pagination grid at the bottom more accessible to screen readers This is done by adding some aria-labels to the buttons of the grid, such as

aria-label="Go to first page"
aria-label="Go to previous page"
aria-label="Go to page 3"

And so on. How do I accomplish that?

Finally, here's the code:

Template:

<!DOCTYPE html>
<html ng-app="todos">

  <head>
   <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
    <script data-require="angular.js@*" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js"></script>
    <script data-require="ui-bootstrap@*" data-semver="0.12.1" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.1.min.js">    </script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="TodoController">
    <h1>Todos</h1>
    <h4>{{todos.length}} total</h4>
    <ul>
      <li ng-repeat="todo in filteredTodos">{{todo.text}}</li>
    </ul>
    <pagination 
      ng-model="currentPage"
      total-items="todos.length"
      max-size="maxSize"  
      boundary-links="true">
    </pagination>
  </body>
</html>

Controller:

var todos = angular.module('todos', ['ui.bootstrap']);

todos.controller('TodoController', function($scope) {
   $scope.filteredTodos = []
  ,$scope.currentPage = 1
  ,$scope.numPerPage = 10
  ,$scope.maxSize = 5;

  $scope.makeTodos = function() {
    $scope.todos = [];
    for (i=1;i<=1000;i++) {
      $scope.todos.push({ text:'todo '+i, done:false});
    }
  };
  $scope.makeTodos(); 

  $scope.$watch('currentPage + numPerPage', function() {
    var begin = (($scope.currentPage - 1) * $scope.numPerPage)
    , end = begin + $scope.numPerPage;

    $scope.filteredTodos = $scope.todos.slice(begin, end);
  });
});
Watchful answered 31/8, 2016 at 8:12 Comment(1)
hi @Ilias, you can use the uib-pagination for angular. Also add ngAria.js from docs.angularjs.org/api/ngAria. Then your control elements will automatically be taken care by ngAria. In this case, the screen reader will read 1,2 and so on.Obvious
F
3

First, let me preface by saying I've never used or looked at angular. Do you have your own copy of angular? Just poking around, the pagination element seems to be generated from a template in template/pagination/pagination.html. When I look at that source, it has stuff like

<li role="menuitem" ng-if="::directionLinks" ng-class="{disabled: noNext()||ngDisabled}" class="pagination-next">
   <a href ng-click="selectPage(page + 1, $event)" ng-disabled="noNext()||ngDisabled" uib-tabindex-toggle>{{::getText('next')}}
   </a>
</li>

Are you allowed to modify the templates? If so, you could add an aria-label to the <a> and even get its text the same way, from paginationConfig.

I found this by poking around ui-bootstrap-tpls-0.12.1.min.js from your plunker example.

Facet answered 31/1, 2017 at 15:52 Comment(3)
Hi @slugolicious, I can change the template but I won't change the min.js file.Obvious
That sounds like a build issue. You'd have to work with how you're building your project and bundling files together.Facet
yes, the template can be changed with the template-url attribute on the angular pagination.Obvious
I
2

Upgrade your ui-bootstrap version, if possible.

Library is right now at v2.4.0 and supports overriding pagination template since v0.14.0

After that, override default template for pagination using template-url.

template-url (Default: uib/template/pagination/pagination.html) - Override the template for the component with a custom provided template

  1. Copy default template in your code base
  2. Modify it as you wish
  3. Add template-url with file path to your <pagination> tag.

PS: Default pagination template is here; Take care to refer docs and template of the version of library you are using.

Edit: Sample from my code using template-url (ui-bootstrap v2.1.4):

<div class="text-center">
   <ul uib-pagination
     total-items="vm.totalCount"
     data-ng-if="vm.totalCount"
     ng-model="vm.page"
     items-per-page="vm.limit"
     boundary-links="true"
     max-size="3"
     template-url="app/core/components/pagination/pagination.html">
   </ul>
</div>
Ibnrushd answered 2/2, 2017 at 23:6 Comment(6)
I think this idea will work. Thank you @Sangharsh. Since the bounty will expire today, I wanted to give you points :). I will mark it correct once it works.Obvious
somehow my pagination is not shown anymore. I added a template in view/pagination.html. And added the template-url in my pagination. It seems that the pagination.html is being loaded. However, the pagination is not visible anymore. This is what I have now for pagination: <uib-pagination ng-change="pageChanged()" ng-show="bigTotalItems > 10" template-url="view/util/pagination.html" rotate="false" total-items="bigTotalItems" ng-model="bigCurrentPage" max-size="maxSize" class="pagination-sm" boundary-links="true" ...>Obvious
uib-pagination directive is restricted to attributes (restrict: 'A'). Please use it with some tag e.g. <ul>.Ibnrushd
Any errors on browser console? Also, which version of UI Bootstrap are you using?Ibnrushd
there is no error on the browser console. I am using bootstrap version Version: 1.3.2Obvious
Glad I could get the ball rolling and contribute the initial idea as well as find the template that needs to be modified and the change required.Facet

© 2022 - 2024 — McMap. All rights reserved.