/**/

最近我有一个任务,我需要将一个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相关问答推荐

正确理解 angular14 中的注入 - 必须从注入上下文中调用注入()

Angular 无法从后端获取数据到前端

无法卸载 angular-cli

Angular2 路由 VS ui-router-ng2 VS ngrx 路由

Angular [disabled]="MyBoolean" 没有工作

如何在 ngFor 循环中创建变量?

material Angular手风琴header/title高度

什么是 Angular 4,我可以从哪里了解更多信息?

在Angular2的 Select 列表中设置最初 Select 的项目

@angular/platform-b​​rowser 与 @angular/platform-b​​rowser-dynamic

Angular 应用程序中的语法错误:Unexpected token <

formGroup 需要一个 FormGroup 实例

Angular 2表单验证重复密码

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

Routing - CanActivate 与 Observable 一起工作

ExpressionChangedAfterItHasBeenCheckedError:表达式在判断后已更改.Previous value: 'undefined'

何时使用 FormGroup 与 FormArray?

无法绑定到“ dataSource”,因为它不是“ table”的已知属性

如何禁用angular2中的输入

*ngIf 和 *ngFor 在同一元素上导致错误