![](/img/trans.png)
[英]Angular 5: “NullInjectorError: No provider for Renderer2” on Component
[英]Service: No provider for Renderer2
Angular 4.2
与Typescript 2.3
我正在重构一个服务,负责创建一个新的脚本标签并将其添加到文档中。
这是旧代码:
loadScript(src:string){
const script = document.createElement('script');
document.body.appendChild(script);
script.src = src;
}
现在,我想使用Renderer2
来避免直接进行 DOM 操作。 所以我在我的服务中注入了我需要的东西并更新了代码:
constructor(private renderer:Renderer2, @Inject(DOCUMENT) private document){}
loadScript(src:string){
const script = this.renderer.createElement('script');
this.renderer.appendChild(this.document.body,script);
script.src = src;
}
但是,我遇到了这个错误:
错误:没有 Renderer2 的提供者!
该服务属于CoreModule
,其唯一导入是来自@angular/common
的CommonModule
这个 plunkr演示了这个问题
可能与Using Renderer in Angular 4重复
您不能注入Renderer2
,但我们可以运行RendererFactory2
以在@Injectable()
服务中获取Renderer2
实例。 有两种不同的方法可以解决这个问题。
例如,Angular 在 webworkers 内部使用的方式。 我已经用下面的代码解决了这个问题:
import { Injectable, Renderer2, RendererFactory2 } from '@angular/core';
@Injectable()
class Service {
private renderer: Renderer2;
constructor(rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
}
}
在您的特定情况下,它将是
@Injectable()
class Service {
private renderer: Renderer2;
constructor(rendererFactory: RendererFactory2, @Inject(DOCUMENT) private document){
this.renderer = rendererFactory.createRenderer(null, null);
}
loadScript(src:string){
const script = this.renderer.createElement('script');
this.renderer.appendChild(this.document.body,script);
script.src = src;
}
}
RendererFactory2.createRenderer
方法的参数是:
hostElement
类型any
主机元素type
为RendererType2|null
您可以看到(null, null)
参数在这里: https ://github.com/angular/angular/blob/e3140ae888ac4037a5f119efaec7b1eaf8726286/packages/core/src/render/api.ts#L129
// declare public property in your service
@Injectable()
class Service {
renderer: Renderer;
}
// pass renderer to service in your component file
class App {
name:string;
constructor(service: Service, renderer: Renderer2) {
service.renderer = renderer;
}
}
您可以使用根组件中的Renderer2
实例初始化服务
@Injectable()
class MyService {
renderer : Renderer2;
}
...
class App {
name:string;
constructor(service: MyService, renderer: Renderer2) {
service.renderer = renderer;
}
}
也可以看看
我尝试使用 render2 来实现它,但在服务中 - 导致“StaticInjectorError(AppModule)[Renderer2]”错误,因为注入 Renderer2-Instance 似乎是不可能的。 解决方案是注入 RendererFactory2 并在服务中手动创建引用,例如:
@Injectable({
providedIn: 'root'
})
export class FgRendererService {
/** Reference to render-instance */
public renderer: Renderer2;
/** CONSTRUCTOR */
constructor(
private _renderer: RendererFactory2
) {
this.renderer = _renderer.createRenderer(null, null);
}
/** Add class to body-tag */
addBodyClass( classToAdd: string ): void {
this.renderer.addClass( document.body, classToAdd );
}
/** Remove class from body-tag */
removeBodyClass( classToRemove: string ): void {
this.renderer.removeClass( document.body, classToRemove );
}
}
无论哪种方法适合您的需求,重要的是要认识到Renderer2
可以有许多不同的实现DefaultDomRenderer2
、 BaseAnimationRenderer
、 DebugRenderer2
、 EmulatedEncapsulationDomRenderer2
等。例如,每个使用 ViewEncapsulation 的组件都有不同的渲染器。
如果您在兄弟组件提供的服务中注入 Renderer2,那么您将自动获得该组件的渲染器。 这对于 ViewEncapsulation 很重要,因为它是真正知道如何生成那些_ngcontent-appName-c339
属性的渲染器。
如果您在根级别、祖先组件或您的AppComponent
注入Renderer2
,然后尝试使用它来生成 HTML,您要么没有主机属性,要么更糟糕的是得到错误的主机属性。
如果也使用 SSR 或网络工作者,请务必仔细测试您的期望。
这些对于您正在做的事情可能都不重要,但重要的是要了解存在不同Renderer2
实例的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.