How to load external scripts dynamically in Angular?

前端 未结 15 767
被撕碎了的回忆
被撕碎了的回忆 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 07:07

    You can load multiple scripts dynamically like this in your component.ts file:

     loadScripts() {
        const dynamicScripts = [
         'https://platform.twitter.com/widgets.js',
         '../../../assets/js/dummyjs.min.js'
        ];
        for (let i = 0; i < dynamicScripts.length; i++) {
          const node = document.createElement('script');
          node.src = dynamicScripts[i];
          node.type = 'text/javascript';
          node.async = false;
          node.charset = 'utf-8';
          document.getElementsByTagName('head')[0].appendChild(node);
        }
      }
    

    and call this method inside the constructor,

    constructor() {
        this.loadScripts();
    }
    

    Note : For more scripts to be loaded dynamically, add them to dynamicScripts array.

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

    a sample can be

    script-loader.service.ts file

    import {Injectable} from '@angular/core';
    import * as $ from 'jquery';
    
    declare let document: any;
    
    interface Script {
      src: string;
      loaded: boolean;
    }
    
    @Injectable()
    export class ScriptLoaderService {
    public _scripts: Script[] = [];
    
    /**
    * @deprecated
    * @param tag
    * @param {string} scripts
    * @returns {Promise<any[]>}
    */
    load(tag, ...scripts: string[]) {
    scripts.forEach((src: string) => {
      if (!this._scripts[src]) {
        this._scripts[src] = {src: src, loaded: false};
      }
    });
    
    let promises: any[] = [];
    scripts.forEach((src) => promises.push(this.loadScript(tag, src)));
    
    return Promise.all(promises);
    }
    
     /**
     * Lazy load list of scripts
     * @param tag
     * @param scripts
     * @param loadOnce
     * @returns {Promise<any[]>}
     */
    loadScripts(tag, scripts, loadOnce?: boolean) {
    loadOnce = loadOnce || false;
    
    scripts.forEach((script: string) => {
      if (!this._scripts[script]) {
        this._scripts[script] = {src: script, loaded: false};
      }
    });
    
    let promises: any[] = [];
    scripts.forEach(
        (script) => promises.push(this.loadScript(tag, script, loadOnce)));
    
    return Promise.all(promises);
    }
    
    /**
     * Lazy load a single script
     * @param tag
     * @param {string} src
     * @param loadOnce
     * @returns {Promise<any>}
     */
    loadScript(tag, src: string, loadOnce?: boolean) {
    loadOnce = loadOnce || false;
    
    if (!this._scripts[src]) {
      this._scripts[src] = {src: src, loaded: false};
    }
    
    return new Promise((resolve, reject) => {
      // resolve if already loaded
      if (this._scripts[src].loaded && loadOnce) {
        resolve({src: src, loaded: true});
      }
      else {
        // load script tag
        let scriptTag = $('<script/>').
            attr('type', 'text/javascript').
            attr('src', this._scripts[src].src);
    
        $(tag).append(scriptTag);
    
        this._scripts[src] = {src: src, loaded: true};
        resolve({src: src, loaded: true});
      }
     });
     }
     }
    

    and usage

    first inject

      constructor(
      private _script: ScriptLoaderService) {
      }
    

    then

    ngAfterViewInit()  {
    this._script.loadScripts('app-wizard-wizard-3',
    ['assets/demo/default/custom/crud/wizard/wizard.js']);
    
    }
    

    or

        this._script.loadScripts('body', [
      'assets/vendors/base/vendors.bundle.js',
      'assets/demo/default/base/scripts.bundle.js'], true).then(() => {
      Helpers.setLoading(false);
      this.handleFormSwitch();
      this.handleSignInFormSubmit();
      this.handleSignUpFormSubmit();
      this.handleForgetPasswordFormSubmit();
    });
    
    0 讨论(0)
  • 2020-11-22 07:13

    You can use following technique to dynamically load JS scripts and libraries on demand in your Angular project.

    script.store.ts will contain the path of the script either locally or on a remote server and a name that will be used to load the script dynamically

     interface Scripts {
        name: string;
        src: string;
    }  
    export const ScriptStore: Scripts[] = [
        {name: 'filepicker', src: 'https://api.filestackapi.com/filestack.js'},
        {name: 'rangeSlider', src: '../../../assets/js/ion.rangeSlider.min.js'}
    ];
    

    script.service.ts is an injectable service that will handle the loading of script, copy script.service.ts as it is

    import {Injectable} from "@angular/core";
    import {ScriptStore} from "./script.store";
    
    declare var document: any;
    
    @Injectable()
    export class ScriptService {
    
    private scripts: any = {};
    
    constructor() {
        ScriptStore.forEach((script: any) => {
            this.scripts[script.name] = {
                loaded: false,
                src: script.src
            };
        });
    }
    
    load(...scripts: string[]) {
        var promises: any[] = [];
        scripts.forEach((script) => promises.push(this.loadScript(script)));
        return Promise.all(promises);
    }
    
    loadScript(name: string) {
        return new Promise((resolve, reject) => {
            //resolve if already loaded
            if (this.scripts[name].loaded) {
                resolve({script: name, loaded: true, status: 'Already Loaded'});
            }
            else {
                //load script
                let script = document.createElement('script');
                script.type = 'text/javascript';
                script.src = this.scripts[name].src;
                if (script.readyState) {  //IE
                    script.onreadystatechange = () => {
                        if (script.readyState === "loaded" || script.readyState === "complete") {
                            script.onreadystatechange = null;
                            this.scripts[name].loaded = true;
                            resolve({script: name, loaded: true, status: 'Loaded'});
                        }
                    };
                } else {  //Others
                    script.onload = () => {
                        this.scripts[name].loaded = true;
                        resolve({script: name, loaded: true, status: 'Loaded'});
                    };
                }
                script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'});
                document.getElementsByTagName('head')[0].appendChild(script);
            }
        });
    }
    
    }
    

    Inject this ScriptService wherever you need it and load js libs like this

    this.script.load('filepicker', 'rangeSlider').then(data => {
        console.log('script loaded ', data);
    }).catch(error => console.log(error));
    
    0 讨论(0)
  • 2020-11-22 07:14

    @rahul-kumar 's solution works good for me, but i wanted to call my javascript function in my typescript

    foo.myFunctions() // works in browser console, but foo can't be used in typescript file
    

    I fixed it by declaring it in my typescript :

    import { Component } from '@angular/core';
    import { ScriptService } from './script.service';
    declare var foo;
    

    And now, i can call foo anywhere in my typecript file

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

    I have done this code snippet with the new renderer api

     constructor(private renderer: Renderer2){}
    
     addJsToElement(src: string): HTMLScriptElement {
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = src;
        this.renderer.appendChild(document.body, script);
        return script;
      }
    

    And then call it like this

    this.addJsToElement('https://widgets.skyscanner.net/widget-server/js/loader.js').onload = () => {
            console.log('SkyScanner Tag loaded');
    } 
    

    StackBlitz

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

    This might work. This Code dynamically appends the <script> tag to the head of the html file on button clicked.

    const url = 'http://iknow.com/this/does/not/work/either/file.js';
    
    export class MyAppComponent {
        loadAPI: Promise<any>;
    
        public buttonClicked() {
            this.loadAPI = new Promise((resolve) => {
                console.log('resolving promise...');
                this.loadScript();
            });
        }
    
        public loadScript() {
            console.log('preparing to load...')
            let node = document.createElement('script');
            node.src = url;
            node.type = 'text/javascript';
            node.async = true;
            node.charset = 'utf-8';
            document.getElementsByTagName('head')[0].appendChild(node);
        }
    }
    
    0 讨论(0)
提交回复
热议问题