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

列表和映射的SCSS语法

当信号的值发生变化时,模板不会更新

Angular ngSubmit 不起作用(内部按钮和导入模块)

错误:在@angular/core中找不到导出ɵivyEnabled(导入为ɵivyEnabled)

iss 声明无效 Keycloak

RxJS - .withLatestFrom 的多个来源

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

类型错误:无法读取未定义的属性

取消订阅服务中的http observable

如何在 Angular 4 中使用 Material Design 图标?

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

NG 测试中的调试测试

Angular 5 测试:如何获取对子组件的引用

Angular2:无法读取未定义的属性名称

来自 chokidar (C:\) 的错误:错误:EBUSY:资源繁忙或锁定,lstat 'C:\DumpStack.log.tmp

重置表单的最简洁方法

服务相互依赖

如何有条件地禁用 routerLink 属性?

如何绑定到 angular2 中的 data-* 属性?

找不到模块 'angular2-in-memory-web-api'