Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Angular MatDialog from custom class (not included in app.module.ts)

I would like to call MatDialog service from my custom class that is extended by Quills BlockEmbed. Objects of my custom class are invoked by Quill editor, and class itself isn't registered anywhere. The problem is i have no idea how to Inject MatDialog component/service properly.

First of my simplified class (custom-class.ts) looks like this:

import { Injector } from '@angular/core';
import { MatDialog } from '@angular/material';
import { DialogContentComponent } from '../dialog-content-component/dialog-content-component';
import Quill from 'quill';

const BlockEmbed = Quill.import('blots/block/embed');

export class AssideBlot extends BlockEmbed {
    static blotName = 'eAside';
    static tagName = 'element-article';
    static className = 'aside-articles';

    static create(articleIdArray: any) {
        // some quills stuff
        const injector = Injector.create({ providers: [{ provide: MatDialog, deps: [] }] });
        const dialog: MatDialog = injector.get(MatDialog);

        const dialogRef = this.dialog.open(DialogContentComponent, {
            data: {},
            height: 'auto',
            maxWidth: '100vw',
            width: '600px',
            panelClass: 'mat-dialog-no-gutter'
          });

          dialogRef.afterClosed().subscribe(result => {
            // some logic
          });
        // More logic
    }
    // More quills stuff
}

I cannot use constructor at any means :/ Quills errors. Anyway, as you might see I've decided to use Injector class, to inject MatDialog. However, even if object is created i cannot open dialog ->

ERROR TypeError: Cannot read property 'position' of undefined
    at MatDialog.push../node_modules/@angular/material/esm5/dialog.es5.js.MatDialog._getOverlayConfig (dialog.es5.js:946)
    at MatDialog.push../node_modules/@angular/material/esm5/dialog.es5.js.MatDialog._createOverlay (dialog.es5.js:923)
    at MatDialog.push../node_modules/@angular/material/esm5/dialog.es5.js.MatDialog.open (dialog.es5.js:846)
    at HTMLButtonElement.<anonymous> (AsideArticleBlot.ts:36)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17290)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:498)
    at invokeTask (zone.js:1744)
    at HTMLButtonElement.globalZoneAwareCallback (zone.js:1781)

At this point i have no idea if i am using Injector correctly or even if what I want is possible. Any suggestions are welcome :)

like image 912
lemek Avatar asked Nov 06 '22 16:11

lemek


1 Answers

I got the same issue, after checking the classes it looks like injector is not providing the dependency classes. So, what i have done in order to make it work is below:

export class AppModule {
  constructor(public dialog: MatDialog) {
    ServiceLocator.injector = Injector.create({
      providers:
        Object.keys(services).map(key => ({
          provide: services[key].provide,
          useClass: services[key].provide,
          deps: services[key].deps
        }))
    }
    );
    ServiceLocator.dialog = dialog;
  }
}

create service.locator.class.ts

import { MatDialog } from '@angular/material/dialog';
import { Injector } from "@angular/core";

export class ServiceLocator {
    static injector: Injector;
    static dialog: MatDialog;
}

My Custom Extended Component class

import { MatDialog } from "@angular/material/dialog";
import { ServiceLocator } from "../services/service.locator.class";

export class ExtendedComponent {
    protected dialog: MatDialog;

    constructor() {
        this.dialog = ServiceLocator.dialog;
    }

    /**
     * Shows given component into popup modal
     *
     * @protected
     * @param {*} modelComponent
     * @memberof ExtendedComponent
     */
    protected OpenDialog(modelComponent: any): void {
        this.dialog.open(modelComponent);
    }
}

Usages

import { Component, OnInit } from '@angular/core';
import { ExtendedComponent } from '../../shared/extended.component';
import { AboutUsComponent } from '../about-us/about-us.component';

@Component({
  selector: 'app-menu-bar',
  templateUrl: './menu-bar.component.html',
  styleUrls: ['./menu-bar.component.less']
})
export class MenuBarComponent extends ExtendedComponent implements OnInit {

  constructor() {
    super();
  }

  ngOnInit(): void {
  }

  /**
   * Show about us dialog
   *
   * @memberof MenuBarComponent
   */
  ShowAboutUs(): void {
    this.OpenDialog(AboutUsComponent);
  }

}
like image 133
Adeel Rizvi Avatar answered Nov 15 '22 11:11

Adeel Rizvi