Learn how to create an overlay with Angular Material CDK
-
npm install --save @angular/material @angular/cdk @angular/animations
-
Import
OverlayModule
in your app module:
import { OverlayModule } from '@angular/cdk/overlay';
@NgModule({
imports: [
...,
OverlayModule
],
...
})
export class AppModule { }
-
Create a new component (ex: OverlayComponent):
ng generate component overlay
-
Add it to entryComponents in your app module:
import { OverlayModule } from '@angular/cdk/overlay';
import { OverlayComponent } from 'overlay/overlay.component';
@NgModule({
imports: [
...,
OverlayModule
],
entryComponents: [
OverlayComponent
...
})
export class AppModule { }
- Add cdkOverlayOrigin to an element of the template:
<button cdkOverlayOrigin (click)="displayOverlay()">Click me!</button>
- Import the following:
import { Component, ViewChild, ViewContainerRef } from '@angular/core';
import { OverlayRef, CdkOverlayOrigin, Overlay, OverlayConfig } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { OverlayComponent } from './overlay/overlay.component'; // replace by your component
- Create displayOverlay function in parent component
export class AppComponent {
overlayRef: OverlayRef;
@ViewChild(CdkOverlayOrigin) _overlayOrigin: CdkOverlayOrigin;
constructor(
public overlay: Overlay,
public viewContainerRef: ViewContainerRef
) { }
displayOverlay() {
const strategy = this.overlay.position().connectedTo(
this._overlayOrigin.elementRef,
{ originX: 'end', originY: 'top' },
{ overlayX: 'end', overlayY: 'top' }
);
const config = new OverlayConfig({
positionStrategy: strategy,
hasBackdrop: true,
backdropClass: 'transparent'
});
this.overlayRef = this.overlay.create(config);
this.overlayRef.attach(
new ComponentPortal(OverlayComponent, this.viewContainerRef)
);
this.overlayRef.backdropClick().subscribe(() => this.overlayRef.detach()); // Allows to close overlay by clicking around it
}
}
- Create a file tokens.ts and add this content:
import { InjectionToken } from '@angular/core';
export const CONTAINER_DATA = new InjectionToken<any>('CONTAINER_DATA');
- Add an injection function to your parent component
import { ..., Injector } from '@angular/core';
import { ..., PortalInjector } from '@angular/cdk/portal';
import { CONTAINER_DATA } from './tokens';
constructor (
...,
private injector: Injector
) { }
createInjector(data: any, overlayRef: OverlayRef): PortalInjector {
const injectorTokens = new WeakMap();
injectorTokens.set(OverlayRef, overlayRef);
injectorTokens.set(CONTAINER_DATA, data);
return new PortalInjector(this.injector, injectorTokens);
}
- Inject data within the displayOverlay() function
...
this.overlayRef.attach(
new ComponentPortal(OverlayComponent, this.viewContainerRef,
this.createInjector({ data: 'Your data' }, this.overlayRef) // this is new
)
);
...
- Get data in overlay component
import { ..., Inject } from '@angular/core';
import { OverlayRef } from '@angular/cdk/overlay';
import { CONTAINER_DATA } from '../tokens';
...
constructor(
@Inject(CONTAINER_DATA) public data: any, // Here are your data
public overlayRef: OverlayRef
) { }
close() {
this.overlayRef.detach(); // Close overlay from the component itself
}
...
- Display it in the overlay template
<div class="overlay-container">
<p>This is the injected data: {{ data.data }}</p>
<div>
<button mat-raised-button (click)="close()">Close me!</button>
</div>
</div>