1
votes

I am trying to create a service to inject a <script></script> in my DOM, instead of doing this via my Component.

My implementation of Renderer2 works perfectly when using it in a Component, but when using Rendere2 via a service I get this error:

core.js:15724 ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[ContactUsPageComponent -> Renderer2]:
StaticInjectorError(Platform: core)[ContactUsPageComponent -> Renderer2]: NullInjectorError: No provider for Renderer2! Error: StaticInjectorError(AppModule)[ContactUsPageComponent -> Renderer2]:
StaticInjectorError(Platform: core)[ContactUsPageComponent -> Renderer2]:

I have tried importing Renderer2 in my AppModule, but get this notification:

(alias) class Renderer2 import Renderer2 Extend this base class to implement custom rendering. By default, Angular renders a template into DOM. You can use custom rendering to intercept rendering calls, or to render to something other than DOM.

Create your custom renderer using RendererFactory2.

Use a custom renderer to bypass Angular's templating and make custom UI changes that can't be expressed declaratively. For example if you need to set a property or an attribute whose name is not statically known, use the setProperty() or setAttribute() method.

This is my service implementation:

import { Injectable, Renderer2, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Injectable({
  providedIn: 'root'
})
export class ChatbotService {

  constructor(private renderer2: Renderer2, @Inject(DOCUMENT) private document) {}

  showChatbot() {
    const s = this.renderer2.createElement('script');
    s.type = 'text/javascript';
    s.id = 'ze-snippet';
    s.src = 'https://static.zdassets.com/ekr/snippet.js?key=7e...';
    s.text = ``;
    this.renderer2.appendChild(this.document.body, s);
  }
}

And I simply call it from a component using: this.chatbotService.showChatbot();

Any suggestions o how to implement this correctly would be greatly appreciated!

1

1 Answers

4
votes

Here is the answer to my question:

NOTE: to use Renderer2 in a service, you need to create an instance of Renderer2, using RendererFactory2. From there it is straight forward.

Here is my Service code:

import { Injectable, Renderer2, RendererFactory2, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Injectable({
  providedIn: 'root'
})
export class ChatbotService {
  private renderer: Renderer2;

  constructor(private rendererFactory: RendererFactory2, @Inject(DOCUMENT) private document) {
    this.renderer = rendererFactory.createRenderer(null, null);
  }

  showChatbot() {
    const s = this.renderer.createElement('script');
    s.type = 'text/javascript';
    s.id = 'ze-snippet';
    s.src = 'https://static.zdassets.com/ekr/snippet.js?key=7e...';
    s.text = ``;
    this.renderer.appendChild(this.document.body, s);
  }
}

Here is my Component call: this.chatbotService.showChatbot();

Hope this helps someone else!