How to load external scripts dynamically in Angular?

前端 未结 15 765
被撕碎了的回忆
被撕碎了的回忆 2020-11-22 06:48

I have this module which componentize the external library together with additional logic without adding the

相关标签:
15条回答
  • 2020-11-22 06:56

    I have modified @rahul kumars answer, so that it uses Observables instead:

    import { Injectable } from "@angular/core";
    import { Observable } from "rxjs/Observable";
    import { Observer } from "rxjs/Observer";
    
    @Injectable()
    export class ScriptLoaderService {
        private scripts: ScriptModel[] = [];
    
        public load(script: ScriptModel): Observable<ScriptModel> {
            return new Observable<ScriptModel>((observer: Observer<ScriptModel>) => {
                var existingScript = this.scripts.find(s => s.name == script.name);
    
                // Complete if already loaded
                if (existingScript && existingScript.loaded) {
                    observer.next(existingScript);
                    observer.complete();
                }
                else {
                    // Add the script
                    this.scripts = [...this.scripts, script];
    
                    // Load the script
                    let scriptElement = document.createElement("script");
                    scriptElement.type = "text/javascript";
                    scriptElement.src = script.src;
    
                    scriptElement.onload = () => {
                        script.loaded = true;
                        observer.next(script);
                        observer.complete();
                    };
    
                    scriptElement.onerror = (error: any) => {
                        observer.error("Couldn't load script " + script.src);
                    };
    
                    document.getElementsByTagName('body')[0].appendChild(scriptElement);
                }
            });
        }
    }
    
    export interface ScriptModel {
        name: string,
        src: string,
        loaded: boolean
    }
    
    0 讨论(0)
  • 2020-11-22 07:00

    An Angular universal solution; I needed to wait for a particular element to be on the page before loading a script to play a video.

    import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
    import {isPlatformBrowser} from "@angular/common";
    
    @Injectable({
      providedIn: 'root'
    })
    export class ScriptLoaderService {
    
      constructor(
        @Inject(PLATFORM_ID) private platformId: Object,
      ) {
      }
    
      load(scriptUrl: string) {
        if (isPlatformBrowser(this.platformId)) {
          let node: any = document.createElement('script');
          node.src = scriptUrl;
          node.type = 'text/javascript';
          node.async = true;
          node.charset = 'utf-8';
          document.getElementsByTagName('head')[0].appendChild(node);
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-22 07:00

    Hi you can use Renderer2 and elementRef with just a few lines of code:

    constructor(private readonly elementRef: ElementRef,
              private renderer: Renderer2) {
    }
    ngOnInit() {
     const script = this.renderer.createElement('script');
     script.src = 'http://iknow.com/this/does/not/work/either/file.js';
     script.onload = () => {
       console.log('script loaded');
       initFile();
     };
     this.renderer.appendChild(this.elementRef.nativeElement, script);
    }
    

    the onload function can be used to call the script functions after the script is loaded, this is very useful if you have to do the calls in the ngOnInit()

    0 讨论(0)
  • 2020-11-22 07:06

    If you're using system.js, you can use System.import() at runtime:

    export class MyAppComponent {
      constructor(){
        System.import('path/to/your/module').then(refToLoadedModule => {
          refToLoadedModule.someFunction();
        }
      );
    }
    

    If you're using webpack, you can take full advantage of its robust code splitting support with require.ensure :

    export class MyAppComponent {
      constructor() {
         require.ensure(['path/to/your/module'], require => {
            let yourModule = require('path/to/your/module');
            yourModule.someFunction();
         }); 
      }
    }
    
    0 讨论(0)
  • 2020-11-22 07:06

    In my case, I've loaded both the js and css visjs files using the above technique - which works great. I call the new function from ngOnInit()

    Note: I could not get it to load by simply adding a <script> and <link> tag to the html template file.

    loadVisJsScript() {
      console.log('Loading visjs js/css files...');
      let script = document.createElement('script');
      script.src = "../../assets/vis/vis.min.js";
      script.type = 'text/javascript';
      script.async = true;
      script.charset = 'utf-8';
      document.getElementsByTagName('head')[0].appendChild(script);    
    	
      let link = document.createElement("link");
      link.type = "stylesheet";
      link.href = "../../assets/vis/vis.min.css";
      document.getElementsByTagName('head')[0].appendChild(link);    
    }

    0 讨论(0)
  • 2020-11-22 07:07

    Yet another option would be to utilize scriptjs package for that matter which

    allows you to load script resources on-demand from any URL

    Example

    Install the package:

    npm i scriptjs
    

    and type definitions for scriptjs:

    npm install --save @types/scriptjs
    

    Then import $script.get() method:

    import { get } from 'scriptjs';
    

    and finally load script resource, in our case Google Maps library:

    export class AppComponent implements OnInit {
      ngOnInit() {
        get("https://maps.googleapis.com/maps/api/js?key=", () => {
            //Google Maps library has been loaded...
        });
      }
    }
    

    Demo

    0 讨论(0)
提交回复
热议问题