最近我有一个任务,我需要将一个TemplateRef传递给组件,它提供一些服务,比如SomeService.在该模板中,我使用了注入服务SomeService的指令.我最终得到了NullInjectorError分.

所以我的问题是,如何在组件中提供服务,而不是在ViewContent中提供服务.

以下是我正在try 做的事情的最低限度的表示.让我们假设所有组件和指令都在同一个模块中声明.

根组件.这里发生的所有事情是,我将一个模板引用传递给app-Component,并在模板中使用指令.

@Component({
    selector: 'root-component',
    template: `
    <app-component [itemTemplate]="template"></app-component>

    <ng-template #template >
        <div 测试指令>hello</div>
    </ng-template>
    `
})
export class RootComponent {
}

应用程序组件.在这里,我提供SomeService

@Component({
    selector: 'app-component',
    template: `
        <ng-container [ngTemplateOutlet]="itemTemplate"></ng-container>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    providers: [
        SomeService // <-- HERE IS THE SERVICE THAT I'M TRYING TO INJECT INTO DIRECTIVE
    ],
})
export class AppComponent {
    @Input()
    itemTemplate: TemplateRef<unknown> | null = null;

    constructor(
    ) {

    }
}

测试指令

@Directive({
    selector: '[测试指令]'
})
export class TestDirective {
    constructor(
        private _someService: SomeService // <-- THIS CAUSE AN NullInjectorError
    ) {
    }
}

没有必要展示SomeService的实施情况,因为这只是一项常规服务.

如果有不清楚的地方,我很抱歉,这是我在StackOverflow上的第一个问题

Stackblitz here

推荐答案

角形v14溶液

对于Angular 14,您可以通过injectorngTemplateOutlet指令.通过这种方式,将在ng-container内部呈现的embeddedView将引用当前的组件注入器树(并指向组件级别上的注入SomeService提供者).

@Component({
  selector: 'app-component',
  template: `
      <ng-container 
        [ngTemplateOutlet]="itemTemplate"
        [ngTemplateOutletInjector]="injector">
      </ng-container>
  `,
  ...
})
export class AppComponent {
  @Input()
  itemTemplate: TemplateRef<unknown> | null = null;

  constructor(
    public readonly injector: Injector
  ) {}
}


Angular V13或更小

您必须对传递模板的方式进行一些更改.而不是将TemplateRef作为Input绑定.将该ng-template作为内容投影传递.

@Component({
  selector: 'root-component',
  template: `
  <app-component>
    <!--Pass template as content projection-->
    <ng-template #template>
      <div testDirective>hello</div>
    </ng-template>
  </app-component>
  `,
})
export class RootComponent {}

然后AppComponent可以使用@ContentChild来查找转换的视图(NG模板)事物判断#template模板变量.就是这样.只要ContentChild查询检索到结果,itemTemplate就会填写.Boom????????

@Component({
  selector: 'app-component',
  ...
})
export class AppComponent {
  // VVVV change here to ContentChild
  @ContentChild('template')
  itemTemplate: TemplateRef<unknown>;
}

在本例中,模板是AppComponent的一部分,注射器树正确地解析SomeService.

Demo

Angular相关问答推荐

如何避免使用CSS动画制作的幻灯片中闪烁?

tabindex on button on button in MatMenu in angular不工作

带信号数据源的17角material 表

Angular 17+独立配置中main.ts bootstrap 调用的最佳实践

无法在Mat-SideNav中绑定模式

错误TS2531:对象可能为空.论窗体数组控件

Angular 单位测试表

Angular 15 在 URL 中使用@进行路由

如何在独立组件中导入Angular innerHTML

如何在Cypress 测试中切换 Angular 选项卡

Angular 从 13.3.8 恢复到 13.3.7

多个 Mat Paginator 在 Angular 组件中不起作用

Observable .do() 运算符 (rxjs) 的用例

如何修复 [Object: null prototype] { title: 'product' }

将查询参数附加到 URL

如何在 bootstrap Angular 2 应用程序时调用休息 api

当父组件上的变量发生变化时重新加载子组件

Angular 2 - 全局 CSS 文件

'ng' 不是内部或外部命令、可运行程序或批处理文件

Angular2 - 如何从应用程序外部调用组件功能