Skip to content

Commit 38d93a8

Browse files
committed
fixup! fix(material/progress-bar): add accessible label for screen readers
1 parent 0dcf46b commit 38d93a8

File tree

5 files changed

+40
-10
lines changed

5 files changed

+40
-10
lines changed

src/dev-app/progress-bar/progress-bar-demo.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ <h1>Buffer</h1>
3636

3737
<div class="demo-progress-bar-container">
3838
<mat-progress-bar [value]="bufferProgressValue" [bufferValue]="bufferBufferValue" mode="buffer"
39-
[color]="color" (animationEnd)="bufferAnimationEndValue = $event.value">
39+
[color]="color" (animationEnd)="bufferAnimationEndValue = $event.value" [attr.aria-label]="label">
4040
</mat-progress-bar>
41+
<button (click)="changeAriaLabel('new label')">change</button>
42+
<button (click)="changeAriaLabel()">clear</button>
4143
</div>
4244

4345
<h1>Indeterminate</h1>

src/dev-app/progress-bar/progress-bar-demo.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class ProgressBarDemo {
2424
bufferAnimationEndValue: number;
2525
bufferProgressValue: number = 30;
2626
bufferBufferValue: number = 40;
27+
label?: string = 'old label';
2728

2829
stepDeterminateProgressVal(val: number) {
2930
this.determinateProgressValue = this._clampValue(val + this.determinateProgressValue);
@@ -37,6 +38,10 @@ export class ProgressBarDemo {
3738
this.bufferBufferValue = this._clampValue(val + this.bufferBufferValue);
3839
}
3940

41+
changeAriaLabel(value?: string) {
42+
this.label = value;
43+
}
44+
4045
private _clampValue(value: number) {
4146
return Math.max(0, Math.min(100, value));
4247
}

src/material/progress-bar/progress-bar.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
<rect [attr.fill]="_rectangleFillValue" width="100%" height="100%"/>
1212
</svg>
1313
<div class="mat-progress-bar-accessible-label cdk-visually-hidden">
14-
{{this.ariaLabel}}{{(this.mode === "indeterminate" || this.mode === "query") ? ' ' : value + '%'}}
14+
<span class="mat-progress-bar-accessible-label__label"></span>
15+
<span>{{(this.mode === "indeterminate" || this.mode === "query") ? null : value + '%'}}</span>
1516
</div>
1617
<div class="mat-progress-bar-buffer mat-progress-bar-element" [ngStyle]="_bufferTransform()"></div>
1718
<div class="mat-progress-bar-primary mat-progress-bar-fill mat-progress-bar-element" [ngStyle]="_primaryTransform()" #primaryValueBar></div>

src/material/progress-bar/progress-bar.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ describe('MatProgressBar', () => {
278278

279279
});
280280

281-
@Component({template: '<mat-progress-bar [aria-label]="demoAriaLabel"></mat-progress-bar>'})
281+
@Component({template: '<mat-progress-bar [attr.aria-label]="demoAriaLabel"></mat-progress-bar>'})
282282
class BasicProgressBar {
283283
demoAriaLabel = '';
284284
}

src/material/progress-bar/progress-bar.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {coerceNumberProperty, NumberInput} from '@angular/cdk/coercion';
99
import {DOCUMENT} from '@angular/common';
1010
import {
1111
AfterViewInit,
12-
ChangeDetectionStrategy,
12+
ChangeDetectionStrategy, ChangeDetectorRef,
1313
Component,
1414
ElementRef,
1515
EventEmitter,
@@ -26,8 +26,8 @@ import {
2626
} from '@angular/core';
2727
import {CanColor, CanColorCtor, mixinColor} from '@angular/material/core';
2828
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
29-
import {fromEvent, Observable, Subscription} from 'rxjs';
30-
import {filter} from 'rxjs/operators';
29+
import {fromEvent, Observable, Subject, Subscription} from 'rxjs';
30+
import {filter, takeUntil} from 'rxjs/operators';
3131

3232

3333
// TODO(josephperrott): Benchpress tests.
@@ -82,6 +82,18 @@ export type ProgressBarMode = 'determinate' | 'indeterminate' | 'buffer' | 'quer
8282
/** Counter used to generate unique IDs for progress bars. */
8383
let progressbarId = 0;
8484

85+
86+
function readAriaValues(element: HTMLElement): Observable<string> {
87+
const config = {attributeFilter: ['aria-label']};
88+
return new Observable((observer) => {
89+
const mutation = new MutationObserver((mutations) => {
90+
const newLabel = (mutations[0].target as HTMLElement).getAttribute('aria-label') ?? '';
91+
observer.next(newLabel);
92+
});
93+
mutation.observe(element, config);
94+
});
95+
}
96+
8597
/**
8698
* `<mat-progress-bar>` component.
8799
*/
@@ -92,7 +104,6 @@ let progressbarId = 0;
92104
'role': 'progressbar',
93105
'aria-valuemin': '0',
94106
'aria-valuemax': '100',
95-
'[attr.aria-label]': 'ariaLabel',
96107
'[attr.aria-valuenow]': '(mode === "indeterminate" || mode === "query") ? null : value',
97108
'[attr.mode]': 'mode',
98109
'class': 'mat-progress-bar',
@@ -125,14 +136,22 @@ export class MatProgressBar extends _MatProgressBarMixinBase implements CanColor
125136
const path = location ? location.getPathname().split('#')[0] : '';
126137
this._rectangleFillValue = `url('${path}#${this.progressbarId}')`;
127138
this._isNoopAnimation = _animationMode === 'NoopAnimations';
139+
const mutationObservable = readAriaValues(_elementRef.nativeElement);
140+
141+
mutationObservable.pipe(takeUntil(this._destroyed)).subscribe((label) => {
142+
console.log(label, this.value);
143+
const accessibleLabel = (_elementRef.nativeElement as HTMLElement)
144+
.getElementsByClassName('mat-progress-bar-accessible-label__label')![0];
145+
accessibleLabel.innerHTML = label;
146+
});
128147
}
129148

149+
/** Subject that emits when the component has been destroyed. */
150+
protected _destroyed = new Subject<void>();
151+
130152
/** Flag that indicates whether NoopAnimations mode is set to true. */
131153
_isNoopAnimation = false;
132154

133-
/** aria-label of progress bar to be set on the host. */
134-
@Input('aria-label') ariaLabel: string = '';
135-
136155
/** Value of the progress bar. Defaults to zero. Mirrored to aria-valuenow. */
137156
@Input()
138157
get value(): number { return this._value; }
@@ -213,6 +232,9 @@ export class MatProgressBar extends _MatProgressBarMixinBase implements CanColor
213232

214233
ngOnDestroy() {
215234
this._animationEndSubscription.unsubscribe();
235+
236+
this._destroyed.next();
237+
this._destroyed.complete();
216238
}
217239

218240
static ngAcceptInputType_value: NumberInput;

0 commit comments

Comments
 (0)