Script Tag in Angular2 Template/Hook When Template Dom Is Loaded

Adding script tags in Angular component template

Maybe a little late to the party here, but since the above answers do not work well with Angular SSR (e.g. document is not defined server-side or document.createElement is not a function), I decided to write a version that works for Angular 4+, in both server and browser context:

Component Implementation

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

class MyComponent implements OnInit {

constructor(
private _renderer2: Renderer2,
@Inject(DOCUMENT) private _document: Document
) { }

public ngOnInit() {

let script = this._renderer2.createElement('script');
script.type = `application/ld+json`;
script.text = `
{
"@context": "https://schema.org"
/* your schema.org microdata goes here */
}
`;

this._renderer2.appendChild(this._document.body, script);
}
}

Service Implementation

NOTE: Services cannot use Renderer2 directly. In fact, rendering an element is supposed to be done by a Component. However, you might find yourself in situation where you want to automate the creation of JSON-LD script tags on a page. As an example, a situation could be to invoke such function on route navigation change events. Hence I decided to add a version that works in a Service context.

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

/**
* Use a Service to automate creation of JSON-LD Microdata.
*/
class MyService {

constructor(
@Inject(DOCUMENT) private _document: Document
) { }

/**
* Set JSON-LD Microdata on the Document Body.
*
* @param renderer2 The Angular Renderer
* @param data The data for the JSON-LD script
* @returns Void
*/
public setJsonLd(renderer2: Renderer2, data: any): void {

let script = renderer2.createElement('script');
script.type = 'application/ld+json';
script.text = `${JSON.stringify(data)}`;

renderer2.appendChild(this._document.body, script);
}
}

Cannot Load .js File in Angular Module

Your script snippet does not "depend" on your component in your example snippet. You are requesting any input with type "range" in the whole web page (document's root) and that is not necessarily your component. (If you have 10 input[type="range"] in your page, the script will have to handle that somehow, or it will only get the first one).

The way to do what you are trying to do IS to put it in the assets folder. If that is forbidden by any project rule, you have two options:

  1. Upload your sidebar.js file into a different server or a different path and host it from there. Since it seems you don't have control over the files in your customer server, you can't make the assumption that the /src/app/ directory is present (since it is not necessary to run the app after it has been built)

  2. Transform your .js file into a typescript file (.ts) and import it so that typescript can compile it.

To transform it into a .js file, just rename the file to sidebar.ts and, at the file you want to include it, import for side effects only

What I recommend is that you wrap your file in a callable function that receives your component reference as a parameter so that you can specify which element is to related to as opposed to let it find in the document root but I suspect that would involve messing with the internals of the sidebar.js file. However if the sidebar file is a library or a module, this might be too time-consuming.

Angular 2 execute script after template render

ngAfterViewInit() of AppComponent is a lifecycle callback Angular calls after the root component and its children have been rendered and it should fit for your purpose.

See also https://angular.io/guide/lifecycle-hooks



Related Topics



Leave a reply



Submit