My colleague Roman recently announced the release of our new component library for Angular Taiga UI. The Getting started instructions say that the application needs to be wrapped in a tui-root
. Let's figure out what it does, find out how and why we use portals and what they are in general.
What is a portal?
Imagine a component select
. It has a dropdown with options to choose from. If you store it in the same place in the DOM as the component itself, you can run into a number of problems. Downstream elements can pop out on top, and the container can cut off the content:
z-index
, Z . 100, 10000, 10001. , overflow: hidden
. ?
. z-index
. ยซยป. Root- Taiga UI . :
<tui-scroll-controls></tui-scroll-controls>
<tui-portal-host>
<div class="content"><ng-content></ng-content></div>
<tui-dialog-host></tui-dialog-host>
<ng-content select="tuiOverDialogs"></ng-content>
<tui-notifications-host></tui-notifications-host>
<ng-content select="tuiOverNotifications"></ng-content>
</tui-portal-host>
<ng-content select="tuiOverPortals"></ng-content>
<tui-hints-host></tui-hints-host>
<ng-content select="tuiOverHints"></ng-content>
tui-dialog-host
, tui-portal-host
โ . -. . Taiga UI . . :
@Injectable({
providedIn: 'root',
})
export class TuiPortalService {
private host: TuiPortalHostComponent;
add<C>(componentFactory: ComponentFactory<C>, injector: Injector): ComponentRef<C> {
return this.host.addComponentChild(componentFactory, injector);
}
remove<C>({hostView}: ComponentRef<C>) {
hostView.destroy();
}
addTemplate<C>(templateRef: TemplateRef<C>, context?: C): EmbeddedViewRef<C> {
return this.host.addTemplateChild(templateRef, context);
}
removeTemplate<C>(viewRef: EmbeddedViewRef<C>) {
viewRef.destroy();
}
}
. , , โ . , , .
, - . , ยซยป, .
, . :
. Material .
, . .
.
. , . , requestAnimationFrame
. โ , . . , . , . , . .
:
โ . Obscured. .
, . , .
:
<section
*ngFor="let item of dialogs$ | async"
polymorpheus-outlet
tuiFocusTrap
tuiOverscroll="all"
class="dialog"
role="dialog"
aria-modal="true"
[attr.aria-labelledby]="item.id"
[content]="item.component"
[context]="item"
[@tuiParentAnimation]
></section>
<div class="overlay"></div>
, ngFor
, . , . , . , .
, . Taiga UI โ . - iOS Android. . , .
Observable
. , โ . . . , , DI- POLYMORPHEUS_CONTEXT
. content
observer
. complete
, , next
. , , . :
const DIALOG = new PolymorpheusComponent(MyDialogComponent);
const DEFAULT_OPTIONS: MyDialogOptions = {
label: '',
size: 's',
};
@Injectable({
providedIn: 'root',
})
export class MyDialogService extends AbstractTuiDialogService<MyDialogOptions> {
protected readonly component = DIALOG;
protected readonly defaultOptions = DEFAULT_OPTIONS;
}
.
, Taiga UI, ng-polymorpheus . , , , .
tuiFocusTrap
. , DOM, , . - โ :
@HostListener('window:focusin.silent', ['$event.target'])
onFocusIn(node: Node) {
if (containsOrAfter(this.elementRef.nativeElement, node)) {
return;
}
const focusable = getClosestKeyboardFocusable(
this.elementRef.nativeElement,
false,
this.elementRef.nativeElement,
);
if (focusable) {
focusable.focus();
}
}
root-. root , tuiOverscroll
. CSS- overscroll-behavior. . , , . , , .
: tui-root?
, . , root-. tui-scroll-controls
. , . <ng-content select="tuiOverDialogs"></ng-content>
. Taiga UI. , .
root event manager plugin` DI. โ . , TuiRootModule
BrowserModule
, . : โ .
, root-. Taiga UI open-source, ยซยป npm. StackBlitz-. , , !