How to handle module imports specific to a library in an angular standalone app?

Discussão em 'Angular' iniciado por Otto Abnormalverbraucher, Março 20, 2025.

  1. I have a library material-extension inside my angular workspace, in which I'm creating some components I require but Angular Material is lacking. In this extension I've installed the module ngx-editor, which I require in the library components but not in the project itself. ngx-editor seems to also have automatically installed angular itself as one of its dependencies, so I've also ended up with @angular in the node_modules folder of my library.

    So I've ended up with this structure:

    • workspace
      • node_modules
        • @angular
        • @angular\material
      • projects
        • angular\material-extension
          • node_modules
            • @angular
            • ngx-editor
          • text-editor
        • world-builder
          • src

    I have worked with angular 14 in the past and am now using angular 18, trying to rewrite some old module based code into the new standalone with signals and injection function. I have one instance where I'm creating a custom material dialog, which uses an injection token according to the Angular Material documentation.


    To access the data in your dialog component, you have to use the MAT_DIALOG_DATA injection token:

    import {Component, Inject} from '@angular/core';
    import {MAT_DIALOG_DATA} from '../dialog';

    @Component({
    selector: 'your-dialog',
    template: 'passed in {{ data.name }}',
    })
    export class YourDialog {
    constructor(@Inject(MAT_DIALOG_DATA) public data: {name: string}) { }
    }​

    Which I'm trying to rewrite according to Angular documentation on migration to the inject function.


    Before

    constructor(
    @Inject(DI_TOKEN) @Optional() readonly token: string) {}
    }


    After

    readonly token = inject(DI_TOKEN, { optional: true });​

    So in my case particularly, that is from my old

    constructor(dialogRef: MatDialogRef<MatTextEditorDialogComponent>,
    @Inject(MAT_DIALOG_DATA) data: any) {
    this.color = 'primary';
    this._dialogRef = dialogRef;
    }


    to the new

    import { Component, inject, input, InputSignal } from '@angular/core';
    import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
    import { ThemePalette } from '../../../../../../dist/angular/material-extension';

    @Component({ template: '' })
    export abstract class Dialog {
    public color: InputSignal<ThemePalette> = input<ThemePalette>('primary');
    private _dialogRef: MatDialogRef<Dialog> = inject(MatDialogRef<Dialog>);
    public data: any = inject(MAT_DIALOG_DATA);

    public close(): void {
    this._dialogRef.close();
    }
    }


    However, I'm facing an error here, saying Argument of type 'InjectionToken<any>' is not assignable to parameter of type 'ProviderToken<any>'., which I assume happens due to the fact that MAT_DIALOG_DATA is imported from the workspace's @angular/material node_module folder (as the library doesn't have angular material installed), while the inject() method is imported from the library's own node_module, which works with the library's instance of @angular/core and thus considers the two incompatible (though I do wonder why the MatDialogRef injection works then...?).

    I have worked with Angular's modular approach in the past but am kinda new to the standalone app structure. With modules, each module had its own imports so it made sense to install external modules in library projects (or at least in the library). I'm not sure how to handle this in a standalone app though. Is it even the way to go to have separate node_module folders for a library or should everything just be installed in the workspace? In the former case, how could I tell the library to use the workspace's @angular/core instead of its own? Just remove it from the node_modules folder?

    Continue reading...

Compartilhe esta Página