ionic-framework icon indicating copy to clipboard operation
ionic-framework copied to clipboard

bug: Angular NullInjector when referencing Injection Tokens in modal components

Open dexster opened this issue 1 year ago • 0 comments

Prerequisites

Ionic Framework Version

v7.x

Current Behavior

When an InjectionToken is provided in a context that is not the root context, it is not available in a component created using the ModalController. A NullInjector error is thrown.

Expected Behavior

The token should be available in components created via ModalController.

An injection parameter could be added to the modal options. Modifying the create method like this fixed the issue for me.

create(opts) {
       return super.create({
           ...opts,
           // added the opts.injector. 
           delegate: this.angularDelegate.create(this.environmentInjector, opts.injector || this.injector, 'modal'),
       });
}

// In the component
private environmentInjector = inject(EnvironmentInjector);

constructor(private modalCtrl: ModalController) { }

async openModal() {
    const modal = await this.modalCtrl.create({
      component: ModalExampleComponent,
      injector: this.environmentInjector
});

Steps to Reproduce

  1. Create an InjectionToken and add it to a route provider
export const TEST_DIALOG = new InjectionToken('TEST_DIALOG');

export const remoteRoutes: Route[] = [
    {
        path: '',
        providers: [{provide: TEST_DIALOG, useValue: 'test'}],
        loadComponent: () => import('./dialog.component').then(m => m.DialogComponent)
    }
];
  1. Open a modal that uses the token
@Component({
  selector: 'my-lib',
  standalone: true,
  imports: [CommonModule],
  template: `
    <button (click)="openModal()">Open</button>`,
})
export class DialogComponent {

  private environmentInjector = inject(EnvironmentInjector);

  constructor(private modalCtrl: ModalController) {}

 async openModal() {
    const modal = await this.modalCtrl.create({
      component: ModalExampleComponent,
    });
    modal.present();
  }
}

@Component({
  selector: 'my-lib',
  standalone: true,
  imports: [CommonModule],
  template: `
    <button (click)="openModal()">Open</button>`,
})
export class DialogComponent {

  constructor(private modalCtrl: ModalController) {
  }

  async openModal() {
    const modal = await this.modalCtrl.create({
      component: ModalExampleComponent
    });
    modal.present();
  }
}


@Component({
  selector: 'my-modal',
  template: `<h1>dialog</h1>`,
  standalone: true
})
export class ModalExampleComponent {

  // nullinjector error thrown here 
  testDialog = inject(TEST_DIALOG);

  constructor() {
    console.log('TEST DIALOG: ', this.testDialog);
  }
}

Code Reproduction URL

No response

Ionic Info

Ionic:

Ionic CLI : 7.2.0

Utility:

cordova-res : not installed globally native-run : not installed globally

System:

NodeJS : v20.9.0 npm : 10.1.0 OS : macOS Unknown

Additional Information

No response

dexster avatar Jan 11 '24 16:01 dexster