Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 8a62975

Browse files
committed
docs(step_15): create new step about accessibility
1 parent 7551b89 commit 8a62975

File tree

3 files changed

+330
-3
lines changed

3 files changed

+330
-3
lines changed

docs/app/src/tutorials.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ angular.module('tutorials', [])
66
'step_00', 'step_01', 'step_02', 'step_03', 'step_04',
77
'step_05', 'step_06', 'step_07', 'step_08', 'step_09',
88
'step_10', 'step_11', 'step_12', 'step_13', 'step_14',
9-
'the_end'
9+
'step_15', 'the_end'
1010
];
1111
return {
1212
scope: {},

docs/content/tutorial/step_14.ngdoc

+2-2
Original file line numberDiff line numberDiff line change
@@ -549,8 +549,8 @@ if the animation was canceled or not. Use this function to do any necessary clea
549549
Our application is now much more pleasant to use, thanks to the smooth transitions between pages
550550
and UI states.
551551

552-
There you have it! We have created a web application in a relatively short amount of time. In the
553-
{@link the_end closing notes} we will cover where to go from here.
552+
We are ready for
553+
{@link step_15 step 15} to learn how to fix the accessibility (_a11y_) issues of the application.
554554

555555

556556
<ul doc-tutorial-nav="14"></ul>

docs/content/tutorial/step_15.ngdoc

+327
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
@ngdoc tutorial
2+
@name 15 - Accessibility
3+
@step 15
4+
@description
5+
6+
<ul doc-tutorial-nav="15"></ul>
7+
8+
In this step, we will learn how to fix the accessibility issues in our application.
9+
10+
* We will use the {@link ngAria ngAria} module to enable WAI-ARIA.
11+
* We will fix some issues in the templates.
12+
* We will use the [protractor-accessibility-plugin](protractor-a11y-plugin) to review the accessibility of our application when we run our e2e tests.
13+
14+
<div doc-tutorial-reset="15"></div>
15+
16+
## Why accessibility matters
17+
18+
* [Creating an accessible web - Access iQ](https://www.youtube.com/watch?v=47n0wEcm6JU)
19+
* [Web Accessibility](https://www.youtube.com/watch?v=bEM9Fn9aOG8)
20+
* [Google Accessibility course](https://webaccessibility.withgoogle.com/course)
21+
* [Accessibility in AngularJS and Beyond](http://marcysutton.com/slides/fluent2015/)
22+
* [Apps For All: Coding Accessible Web Applications](https://shop.smashingmagazine.com/products/apps-for-all)
23+
24+
## Main accessibility issues in the application
25+
26+
If you make a review of the accessibility of the application you will find some issues:
27+
28+
* Lack of information about the current results when the user interacts with the filters.
29+
* Lack of labels elements in the search and order filters in the Phone list.
30+
* Lack of headers elements to help the user to navigate throw the content of the page.
31+
* In the Phone detail, the user can't access via keyboard over the thumbnails images.
32+
33+
In the next sections we are going to show you, how to fix some of these issues to make the application accessible.
34+
35+
To help us, we will use the {@link ngAria ngAria} module, and we will install the [protractor-a11y-plugin] plugin too.
36+
37+
## Dependencies
38+
39+
The `ngAria` module, is distributed separately from the core Angular framework.
40+
41+
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
42+
`bower.json` configuration file to include the new dependencies:
43+
44+
<br />
45+
**`bower.json`:**
46+
47+
```
48+
{
49+
"name": "angular-phonecat",
50+
"description": "A starter project for AngularJS",
51+
"version": "0.0.0",
52+
"homepage": "https://github.com/angular/angular-phonecat",
53+
"license": "MIT",
54+
"private": true,
55+
"dependencies": {
56+
"angular": "1.5.x",
57+
"angular-animate": "1.5.x",
58+
"angular-aria": "1.5.x",
59+
"angular-mocks": "1.5.x",
60+
"angular-resource": "1.5.x",
61+
"angular-route": "1.5.x",
62+
"bootstrap": "3.3.x",
63+
"jquery": "2.2.x"
64+
}
65+
}
66+
```
67+
68+
* `"angular-aria": "1.5.x"` tells bower to install a version of the angular-aria module that
69+
is compatible with version 1.5.x of Angular.
70+
71+
To install the [protractor-a11y-plugin], we can add the plugin into the `devDependencies` section in the `package.json` file,
72+
73+
<br />
74+
**`package.json`:**
75+
76+
```
77+
{
78+
"devDependencies": {
79+
"bower": "^1.7.7",
80+
"http-server": "^0.9.0",
81+
"jasmine-core": "^2.4.1",
82+
"karma": "^0.13.22",
83+
"karma-chrome-launcher": "^0.2.3",
84+
"karma-firefox-launcher": "^0.1.7",
85+
"karma-jasmine": "^0.3.8",
86+
"protractor": "^3.2.2",
87+
"protractor-accessibility-plugin": "^0.1.1",
88+
"shelljs": "^0.6.0"
89+
}
90+
}
91+
```
92+
93+
Now, we must tell bower to download and install these dependencies.
94+
95+
```
96+
npm install
97+
```
98+
99+
<div class="alert alert-info">
100+
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
101+
we have preconfigured `npm install` to run bower for us.
102+
</div>
103+
104+
<div class="alert alert-warning">
105+
**Warning:** If a new version of Angular has been released since you last ran `npm install`, then
106+
you may have a problem with the `bower install` due to a conflict between the versions of
107+
angular.js that need to be installed. If you run into this issue, simply delete your
108+
`app/bower_components` directory and then run `npm install`.
109+
</div>
110+
111+
112+
## How to use the `ngAria` module
113+
114+
The `ngAria` module provides support for common ARIA attributes that convey state or semantic information about the application for users of assistive technologies, such as screen readers.
115+
116+
### Template
117+
118+
In order to enable the module, we need to update `index.html`, loading the necessary dependencies
119+
(**angular-aria.js**) that contain JavaScript code.
120+
121+
The WAI-ARIA module, {@link ngAria ngAria}, contains the code necessary to help you to add WAI-ARIA attributes in your application.
122+
123+
<br />
124+
**`app/index.html`:**
125+
126+
```html
127+
...
128+
<!-- Adds WAI-ARIA module in AngularJS -->
129+
<script src="bower_components/angular-aria/angular-aria.js"></script>
130+
...
131+
```
132+
133+
### Dependencies
134+
135+
We need to add a dependency on `ngAria` to our main module first:
136+
137+
<br />
138+
**`app/app.module.js`:**
139+
140+
```js
141+
angular.
142+
module('phonecatApp', [
143+
...
144+
'ngAria',
145+
...
146+
]);
147+
```
148+
149+
## How to inform the user that _something_ is happening
150+
151+
Today, is very common to find applications or webpages where the user make some interaction with an element and obtains and inmediate reply to the action.
152+
153+
The problem is that in most of the cases this action is only reported in a way that you need to see it in your screen but if a user is navigating with a screenreader like [JAWS](http://www.freedomscientific.com/Products/Blindness/JAWS), [NVDA](http://www.nvaccess.org/) or [ChromeVox](http://www.chromevox.com/), this information never won't be accessible.
154+
155+
When the user is searching or filtering mobiles in the application, the list updates automatically. It is mandatory that user knows, in some way, the result after the search or order action.
156+
157+
To fix this, we add two directives to inform the user how many items are know in the list after search or order them. This directive will fill an element in our page to tell the user how many elements are after the action.
158+
159+
<br />
160+
**`app/phone-list/phone-list-template.html`:**
161+
162+
```html
163+
<div>
164+
<label for="search">Search:</label>
165+
<input id="search" ng-model="$ctrl.query" ng-model-options="{ debounce: 900 }">
166+
</div>
167+
168+
<div class="aria-status" aria-live="assertive" aria-atomic="true"></div>
169+
170+
...
171+
172+
<div class="aria-status-sort" aria-live="assertive" aria-atomic="true"></div>
173+
174+
```
175+
176+
The new element is a _region live_. It means that every time this region is updated, it will inform the user about its content.
177+
178+
In order to update the information correctly, it is neccesary to add a _`debounce`_ option to the model.
179+
180+
Please note that now the inputs are associated with theirs labels using `label` elements.
181+
182+
The directives are based on an idea of [Marcy Sutton](http://marcysutton.com/slides/fluent2015/) about how to add accessibility in the AngularJS applications.
183+
184+
185+
### How to use the directives
186+
187+
<br />
188+
**`app/phone-list/phone-list-template.html`:**
189+
190+
```html
191+
192+
...
193+
194+
<div>
195+
<label for="order">Sort by:</label>
196+
<select inform-order id="order" ng-model="$ctrl.orderProp">
197+
<option value="name">Alphabetical</option>
198+
<option value="age">Newest</option>
199+
</select>
200+
</div>
201+
202+
...
203+
204+
<ul result-list class="phones">
205+
<li ng-repeat="phone in filtered = ($ctrl.phones | filter:$ctrl.query | orderBy:$ctrl.orderProp)"
206+
class="thumbnail phone-list-item">
207+
<a href="#!/phones/{{phone.id}}" class="thumb">
208+
<img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}" />
209+
</a>
210+
<a href="#!/phones/{{phone.id}}">{{phone.name}}</a>
211+
<p>{{phone.snippet}}</p>
212+
</li>
213+
</ul>
214+
215+
```
216+
217+
<br />
218+
**`app/index.html`:**
219+
220+
```html
221+
...
222+
<script src="phone-list/phone-list.directive.js"></script>
223+
...
224+
```
225+
226+
227+
<br />
228+
**`app/phone-list/phone-list.directive.js`:**
229+
230+
```js
231+
232+
'use strict';
233+
234+
/* Directives */
235+
236+
angular.
237+
module('phoneList').
238+
directive('resultList', [function () {
239+
var ariaStatus = document.querySelector('.aria-status');
240+
return {
241+
restrict: 'A',
242+
link: function ($scope) {
243+
$scope.$watch('filtered.length', function (length) {
244+
if(length === 1) {
245+
ariaStatus.innerHTML = length + ' item found';
246+
} else if(length > 1) {
247+
ariaStatus.innerHTML = length + ' items found';
248+
} else {
249+
ariaStatus.innerHTML = 'No items found';
250+
}
251+
});
252+
}
253+
}
254+
}
255+
]).
256+
directive('informOrder', [function () {
257+
var ariaStatusSort = document.querySelector('.aria-status-sort');
258+
return {
259+
restrict: 'A',
260+
link: function ($scope) {
261+
$scope.$watch('$ctrl.orderProp', function (order) {
262+
if(order === 'age') {
263+
ariaStatusSort.innerHTML = 'Items filter by newest'
264+
} else {
265+
ariaStatusSort.innerHTML = 'Items filter by alphabetical order'
266+
}
267+
268+
});
269+
}
270+
}
271+
}
272+
]);
273+
274+
```
275+
276+
## Using the keyboard
277+
278+
The current detail of a phone prevents a user to use a keyboard to navigate for over each thumbnail image. It is very important due to accessibility that all the actions and information are available via keyboard too. For example, lightboxes, carousels, slides, etc.
279+
280+
_Tip_: Try to navigate over the application using only the _TAB_ key. You will discover that some actions can't be accessed nor the focus on some elements.
281+
282+
<br />
283+
**`app/phone-detail/phone-detail.template.html`:**
284+
285+
```html
286+
...
287+
<ul class="phone-thumbs">
288+
<li ng-repeat="img in $ctrl.phone.images">
289+
<button type="button" aria-label="view enlarge version of the image" ng-click="$ctrl.setImage(img)"><img ng-src="{{img}}" alt="" /></button>
290+
</li>
291+
</ul>
292+
...
293+
```
294+
295+
## How to run the e2e tests using the Protractor accessibility plugin
296+
297+
Once the plugin is installed, we have to modify the `protractor.conf.js` file to inform Protractor to use this plugin too.
298+
299+
<br />
300+
**`protractor.conf.js`:**
301+
302+
```
303+
plugins: [{
304+
chromeA11YDevTools: {
305+
treatWarningsAsFailures: true
306+
},
307+
package: 'protractor-accessibility-plugin'
308+
}]
309+
```
310+
311+
After that, every time we run the e2e tests, Protractor will review the accessibility of your application using the [Accessibility Developer Tools](https://github.com/GoogleChrome/accessibility-developer-tools).
312+
313+
314+
315+
# Summary
316+
317+
Our application is now accessible, thanks to these small changes.
318+
319+
There you have it! We have created a web application in a relatively short amount of time. In the
320+
{@link the_end closing notes} we will cover where to go from here.
321+
322+
323+
<ul doc-tutorial-nav="15"></ul>
324+
325+
326+
[bower]: http://bower.io/
327+
[protractor-a11y-plugin]: https://github.com/angular/protractor-accessibility-plugin

0 commit comments

Comments
 (0)