Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/layout-test/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ export class AppComponent {
this.modalService
.open({
component: ModalComponent,
label: 'Modal',
role: 'dialog',
panelClass: 'modal-panel',
labelledById: 'test',
})
.pipe(
tap((action) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/layout-test/src/modal/modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { NgxModalAbstractComponent } from '@ngx/inform';
@Component({
selector: 'test-modal',
template: `
Hello world!
<span id="test"> Hello world! </span>
<button (click)="action.emit('Test')">Hello there!</button>
<button (click)="close.emit()">Close</button>
`,
Expand Down
2 changes: 1 addition & 1 deletion libs/inform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ On top of that, by passing a `modals` record, we can define a set preset modals

The `NgxModalService` allows for two ways of opening a modal. Either by opening a predefined modal we set in the configuration, or a custom modal by passing a new modal component.

To make the modals ARIA compliant either a `label` or a `labelledById` must be provided. If the role of a modal was set to `alertdialog`, the `describedById` property is also required.
To make the modals ARIA compliant either a `label` or a `labelledById` must be provided. If the role of a modal was set to `alertdialog`, the `describedById` property is also required. If no element with the provided id was found in the modal, the `ngx-inform` package will throw an error.

When opening a modal we can overwrite all the globally and modal-specific configuration using the same properties as mentioned earlier. On top of that, we can set several other properties. These properties are:

Expand Down
53 changes: 51 additions & 2 deletions libs/inform/src/lib/abstracts/modal/modal.abstract.component.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
import {
AfterViewInit,
Directive,
ElementRef,
EventEmitter,
HostListener,
Inject,
Input,
Output,
PLATFORM_ID,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

import { NgxModalActionType } from '../../types';

/**
* An abstract for the NgxModalService
*/
@Directive()
export class NgxModalAbstractComponent<ActionType extends NgxModalActionType, DataType = any> {
export class NgxModalAbstractComponent<ActionType extends NgxModalActionType, DataType = any>
implements AfterViewInit
{
/**
* Remove the modal on escape pressed
*/
@HostListener('document:keydown.escape') private onEscape() {
this.close.emit();
}

/**
* An optional aria-labelledby property
*/
@Input() public ariaLabelledBy: string;

/**
* An optional aria-describedBy property
*/
@Input() public ariaDescribedBy: string;

/**
* Optional data that can be passed to the modal
*/
Expand All @@ -27,4 +51,29 @@ export class NgxModalAbstractComponent<ActionType extends NgxModalActionType, Da
* An emitter that will emit if the modal is closed
*/
@Output() public close: EventEmitter<void> = new EventEmitter<void>();

constructor(
@Inject(PLATFORM_ID) private platformId: string,
private readonly elementRef: ElementRef<HTMLElement>
) {}

public ngAfterViewInit(): void {
// Iben: If we are in the browser, check if either of the two accessibility labels are set
if (isPlatformBrowser(this.platformId) && (this.ariaLabelledBy || this.ariaDescribedBy)) {
// Iben: Find the element with the id and the parent
const element = document.getElementById(this.ariaLabelledBy || this.ariaDescribedBy);
const parent = this.elementRef.nativeElement;

// Iben: If no corresponding element was found or if it isn't part of the modal, throw an error
if (!element || !parent.contains(element)) {
console.error(
`NgxModalAbstractComponent: The ${
this.ariaLabelledBy ? '"aria-labelledBy"' : 'aria-describedBy'
} property was passed to the modal but no element with said id was found. Because of that, the necessary accessibility attributes could not be set. Please add an id with the value "${
this.ariaLabelledBy || this.ariaDescribedBy
}" to an element of the modal.`
);
}
}
}
}
2 changes: 2 additions & 0 deletions libs/inform/src/lib/services/modal/modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ export class NgxModalService {

// Iben: Set the data of the modal
modal.data = this.getValue(configuration?.data, options.data, undefined);
modal.ariaDescribedBy = options.describedById;
modal.ariaLabelledBy = options.labelledById;

return modal;
}
Expand Down