diff --git a/cspell-wordlist.txt b/cspell-wordlist.txt index bf433d7615..96a53460ab 100644 --- a/cspell-wordlist.txt +++ b/cspell-wordlist.txt @@ -13,6 +13,7 @@ Udemy Vetur Wistia WCAG +CDK actionsheet fabs diff --git a/docs/angular/overlays.md b/docs/angular/overlays.md new file mode 100644 index 0000000000..2b5fdd5f66 --- /dev/null +++ b/docs/angular/overlays.md @@ -0,0 +1,201 @@ +--- +title: Overlay Components +sidebar_label: Overlay Components +--- + + + Angular Overlay Components: Modals, Popovers with Custom Injectors + + + +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: + +```typescript +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 `Dir` directive 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: + +```typescript +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`: + +```typescript +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: + +```typescript +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: + +```typescript +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: + +```typescript +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` - Extends `ModalOptions` with the `injector` property +- `AngularPopoverOptions` - Extends `PopoverOptions` with the `injector` property + +These types are exported from `@ionic/angular` and `@ionic/angular/standalone`: + +```typescript +import type { AngularModalOptions, AngularPopoverOptions } from '@ionic/angular/standalone'; +``` diff --git a/sidebars.js b/sidebars.js index d8cacb1754..06689adc35 100644 --- a/sidebars.js +++ b/sidebars.js @@ -87,6 +87,7 @@ module.exports = { 'angular/build-options', 'angular/lifecycle', 'angular/navigation', + 'angular/overlays', 'angular/injection-tokens', 'angular/virtual-scroll', 'angular/slides',