Overlay Components
Ionic provides overlay components such as modals and popovers that display content on top of your application. In Angular, these overlays can be created using controllers like ModalController and PopoverController.
Creating Overlays
Overlays can be created programmatically using their respective controllers:
import { Component } from '@angular/core';
import { ModalController } from '@ionic/angular/standalone';
import { MyModalComponent } from './my-modal.component';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
})
export class HomeComponent {
constructor(private modalController: ModalController) {}
async openModal() {
const modal = await this.modalController.create({
component: MyModalComponent,
componentProps: {
title: 'My Modal',
},
});
await modal.present();
}
}
Custom Injectors
By default, overlay components use the root injector for dependency injection. This means that services or tokens provided at the route level or within a specific component tree are not accessible inside the overlay.
The injector option allows you to pass a custom Angular Injector when creating a modal or popover. This enables overlay components to access services and tokens that are not available in the root injector.
Use Cases
Custom injectors are useful when you need to:
- Access route-scoped services from within an overlay
- Use Angular CDK's
Dirdirective for bidirectional text support - Access any providers that are not registered at the root level
Usage
To use a custom injector, pass it to the create() method:
import { Component, Injector } from '@angular/core';
import { ModalController } from '@ionic/angular/standalone';
import { MyModalComponent } from './my-modal.component';
import { MyRouteService } from './my-route.service';
@Component({
selector: 'app-feature',
templateUrl: './feature.component.html',
providers: [MyRouteService], // Service provided at route level
})
export class FeatureComponent {
constructor(
private modalController: ModalController,
private injector: Injector
) {}
async openModal() {
const modal = await this.modalController.create({
component: MyModalComponent,
injector: this.injector, // Pass the component's injector
});
await modal.present();
}
}
The modal component can now inject MyRouteService:
import { Component, inject } from '@angular/core';
import { MyRouteService } from '../my-route.service';
@Component({
selector: 'app-my-modal',
templateUrl: './my-modal.component.html',
})
export class MyModalComponent {
private myRouteService = inject(MyRouteService);
}
Creating a Custom Injector
You can also create a custom injector with specific providers:
import { Component, Injector } from '@angular/core';
import { ModalController } from '@ionic/angular/standalone';
import { MyModalComponent } from './my-modal.component';
import { MyService } from './my.service';
@Component({
selector: 'app-feature',
templateUrl: './feature.component.html',
})
export class FeatureComponent {
constructor(
private modalController: ModalController,
private injector: Injector
) {}
async openModal() {
const myService = new MyService();
myService.configure({ someOption: true });
const customInjector = Injector.create({
providers: [{ provide: MyService, useValue: myService }],
parent: this.injector,
});
const modal = await this.modalController.create({
component: MyModalComponent,
injector: customInjector,
});
await modal.present();
}
}
Using with Angular CDK Directionality
A common use case is providing the Angular CDK Dir directive to overlays for bidirectional text support:
import { Component, Injector } from '@angular/core';
import { Dir } from '@angular/cdk/bidi';
import { ModalController } from '@ionic/angular/standalone';
import { MyModalComponent } from './my-modal.component';
@Component({
selector: 'app-feature',
templateUrl: './feature.component.html',
})
export class FeatureComponent {
constructor(
private modalController: ModalController,
private injector: Injector
) {}
async openModal() {
const modal = await this.modalController.create({
component: MyModalComponent,
injector: this.injector, // Includes Dir from component tree
});
await modal.present();
}
}
Popover Controller
The PopoverController supports the same injector option:
import { Component, Injector } from '@angular/core';
import { PopoverController } from '@ionic/angular/standalone';
import { MyPopoverComponent } from './my-popover.component';
@Component({
selector: 'app-feature',
templateUrl: './feature.component.html',
})
export class FeatureComponent {
constructor(
private popoverController: PopoverController,
private injector: Injector
) {}
async openPopover(event: Event) {
const popover = await this.popoverController.create({
component: MyPopoverComponent,
event: event,
injector: this.injector,
});
await popover.present();
}
}
Angular Options Interfaces
Ionic provides Angular-specific option interfaces that extend the core options with Angular-specific properties:
AngularModalOptions- ExtendsModalOptionswith theinjectorpropertyAngularPopoverOptions- ExtendsPopoverOptionswith theinjectorproperty
These types are exported from @ionic/angular and @ionic/angular/standalone:
import type { AngularModalOptions, AngularPopoverOptions } from '@ionic/angular/standalone';