将服务实例传播到对话框组件无法按预期工作

时间:2019-09-24 15:35:08

标签: angular dependency-injection angular-material

我简单地复制了我想在stackblitz上实现的目标: https://stackblitz.com/edit/angular-zb8kvg

我有一个组件(这里是app.component),该组件在(MyService)上声明了服务。 每次打开组件时,我都需要一个MyService的新实例,所以对我来说,该服务是在组件级别而不是在模块级别声明的。

现在,我想从需要相同服务实例的该组件中打开一个对话框(MatDialog-> TestComponent)。

如控制台输出所示,我收到一个StaticInjectorError。

如何在对话框中使用与调用组件相同的服务实例?

4 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,并找到了一个解决方案,允许以通常的方式将服务注入到对话框组件中。传递给 MatDialogConfig 方法的 MatDialog.open 有一个名为 viewContainerRef 的属性,其文档如下:

<块引用>

附加组件应该位于 Angular 的逻辑 组件树中的什么位置。这会影响可用于注入的内容以及在对话框内实例化的组件的更改检测顺序。这不会影响对话框内容的呈现位置。

只需传递当前的 ViewContainerRef(注入到您的宿主组件中),它就会按预期工作:

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
  providers: [MyService]
})
export class AppComponent {
  constructor(public dialog: MatDialog, private viewContainerRef: ViewContainerRef) {}

  open() {
    this.dialog.open(DialogComponent, { viewContainerRef: this.viewContainerRef });
  }
}

@Component({
  template: "<h1>DialogComponent</h1>"
})
export class DialogComponent {
  constructor(private myService: MyService) { }
}

答案 1 :(得分:1)

这是因为即使对话框是从您的app.component请求 的,也不是它的子级。如果您检查对话框的DOM元素,您会看到这一点:该对话框被附加到body的根的某个位置,作为有角应用程序的根元素的同级。

因此依赖项注入按预期工作,只是该服务的范围未涵盖该对话框。

建议的解决方案:您可以在MatDialogConfig的{​​{1}}参数中传递数据,该参数具有一个数据字段。

该数据可以多种方式使用:

  • 您可以从调用对话框的组件传递回调,对话框可以调用该对话框。回调将有权访问注入到调用对话框的组件中的服务。
  • 您可以仅从调用对话框的组件中传递对服务实例的引用,因此对话框中的组件基本上具有完整的服务实例

示例:https://material.angular.io/components/dialog/examples(请参见第一个示例的TS部分)

答案 2 :(得分:0)

您未在组件中提供服务,因为缺少“提供”属性

@Component({
 selector: 'app-test',
 template: '<h1>TestComponent</h1>',
 providers: [MyService] //Missing
 })

答案 3 :(得分:0)

您可以在 Injector(MatDialog -> TestComponent) 参数的帮助下将父 MatDialogConfig(@angular/core/injector) 传递给 MatDialog.open

示例:

app.component.ts

import { Component, Injector } from "@angular/core";
import { MyService } from "./my.service";
import { MatDialog } from "@angular/material";
import { TestComponent } from "./test.component";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
  providers: [MyService]
})
export class AppComponent {
  constructor(public dialog: MatDialog, private injector: Injector) {}

  open() {
    this.dialog.open(TestComponent, { data: { injector: this.injector } });
  }
}

test.component.ts

import { Component, Inject, Injector, OnInit } from "@angular/core";
import { MAT_DIALOG_DATA } from "@angular/material/dialog";
import { MyService } from "./my.service";

@Component({
  selector: "app-test",
  template: "<h1>TestComponent</h1>"
})
export class TestComponent {
  myService: MyService;

  constructor(@Inject(MAT_DIALOG_DATA) public data: { injector: Injector }) {
    this.myService = this.data.injector.get(MyService);
  }
}