How to load external scripts dynamically in Angular?

JavascriptAngularTypescriptEcmascript 6

Javascript Problem Overview


I have this module which componentize the external library together with additional logic without adding the <script> tag directly into the index.html:

import 'http://external.com/path/file.js'
//import '../js/file.js'

@Component({
    selector: 'my-app',
    template: `
        <script src="http://iknow.com/this/does/not/work/either/file.js"></script>
        <div>Template</div>`
})
export class MyAppComponent {...}

I notice the import by ES6 spec is static and resolved during TypeScript transpiling rather than at runtime.

Anyway to make it configurable so the file.js will be loading either from CDN or local folder? How to tell Angular 2 to load a script dynamically?

Javascript Solutions


Solution 1 - Javascript

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));

Solution 2 - Javascript

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();
     }); 
  }
}

Solution 3 - Javascript

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);
	}
}

Solution 4 - Javascript

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

Solution 5 - Javascript

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
}

Solution 6 - Javascript

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.

Solution 7 - Javascript

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()

Solution 8 - Javascript

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

Solution 9 - Javascript

I have a good way to dynamically load scripts! Now I use ng6, echarts4 (>700Kb ) ,ngx-echarts3 in my project. when I use them by ngx-echarts's docs, I need import echarts in angular.json : "scripts":["./node_modules/echarts/dist/echarts.min.js"] thus in the login module, page while loading scripts.js, this is big file! I don't want it.

So, I think angular loads each module as a file, I can insert a router resolver to preload js, then begin the module loading!

// PreloadScriptResolver.service.js

/**动态加载js的服务 */
@Injectable({
  providedIn: 'root'
})
export class PreloadScriptResolver implements Resolve<IPreloadScriptResult[]> {
  // Here import all dynamically js file
  private scripts: any = {
    echarts: { loaded: false, src: "assets/lib/echarts.min.js" }
  };
  constructor() { }
  load(...scripts: string[]) {
    const promises = scripts.map(script => this.loadScript(script));
    return Promise.all(promises);
  }
  loadScript(name: string): Promise<IPreloadScriptResult> {
    return new Promise((resolve, reject) => {
      if (this.scripts[name].loaded) {
        resolve({ script: name, loaded: true, status: 'Already Loaded' });
      } else {
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = this.scripts[name].src;
        script.onload = () => {
          this.scripts[name].loaded = true;
          resolve({ script: name, loaded: true, status: 'Loaded' });
        };
        script.onerror = (error: any) => reject({ script: name, loaded: false, status: 'Loaded Error:' + error.toString() });
        document.head.appendChild(script);
      }
    });
  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<IPreloadScriptResult[]> {
   return this.load(...route.routeConfig.data.preloadScripts);
  }
}

Then in the submodule-routing.module.ts ,import this PreloadScriptResolver:

const routes: Routes = [
  {
    path: "",
    component: DashboardComponent,
    canActivate: [AuthGuardService],
    canActivateChild: [AuthGuardService],
    resolve: {
      preloadScripts: PreloadScriptResolver
    },
    data: {
      preloadScripts: ["echarts"]  // important!
    },
    children: [.....]
}

This code works well, and its promises that: After js file loaded, then module begin load! this Resolver can use in many routers

Solution 10 - Javascript

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);
    }
  }
}

Solution 11 - Javascript

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);    
}

Solution 12 - Javascript

@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

Solution 13 - Javascript

for those of you who would like to load styles dynamically too. (based on @Rahul Kumar brilliant answer)

script.store.ts

interface Scripts {
    name: string;
    src: string;
}

export const StyleStore: Scripts[] = [
    { name: 'fancybox-css', src: 'https://cdn.jsdelivr.net/gh/fancyapps/[email protected]/dist/jquery.fancybox.min.css' }
];

export const ScriptStore: Scripts[] = [
    { name: 'jquery', src: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js' },
    { name: 'other', src: '[other script source]'}
];

script-loader.service.ts

import { Injectable } from '@angular/core';
import { ScriptStore, StyleStore } from '../../stores/script.store';

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

  private scripts: any = {};
  private styles: any = {};

  constructor() {
    ScriptStore.forEach((script: any) => {
      this.scripts[script.name] = {
        loaded: false,
        src: script.src
      };
    });

    StyleStore.forEach((script: any) => {
      this.styles[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);
  }

  loadStyles(...scripts: string[]) {
    var promises: any[] = [];
    scripts.forEach((script) => promises.push(this.loadStyle(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') as any;
        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);
      }
    });
  }

  loadStyle(name: string) {
    return new Promise((resolve, reject) => {
      //resolve if already loaded
      if (this.styles[name].loaded) {
        resolve({ script: name, loaded: true, status: 'Already Loaded' });
      }
      else {
        //load style
        let style = document.createElement('link') as any;
        style.type = "text/css";
        style.rel = "stylesheet";
        style.href = this.styles[name].src;
        if (style.readyState) {  //IE
          style.onreadystatechange = () => {
            if (style.readyState === "loaded" || style.readyState === "complete") {
              style.onreadystatechange = null;
              this.styles[name].loaded = true;
              resolve({ style: name, loaded: true, status: 'Loaded' });
            }
          };
        } else {  //Others
          style.onload = () => {
            this.styles[name].loaded = true;
            resolve({ style: name, loaded: true, status: 'Loaded' });
          };
        }
        style.onerror = (error: any) => resolve({ style: name, loaded: false, status: 'Loaded' });
        document.getElementsByTagName('head')[0].appendChild(style);
      }
    });
  }

}

app.component.ts

constructor(private scriptLoaderService: ScriptLoaderService) {
  this.scriptLoaderService.loadStyles('fancybox-css').then(x => {
    this.scriptLoaderService.load('jquery', 'fancybox').then(data => {
    }).catch(error => console.log(error));
  });
}

Solution 14 - Javascript

I had the same issue for the below link.I solved it in a very easy way.

https://www.gstatic.com/charts/loader.js

I needed to access the google variable in the below code. But it didn't work when I just put it in the angular class.

google.charts.load("current", {packages:['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
    var data = google.visualization.arrayToDataTable([        ["Element", "Density", { role: "style" } ],
        ["Copper", 8.94, "dodgerblue"],
        ["Silver", 10.49, "dodgerblue"],
        ["Gold", 19.30, "dodgerblue"],
        ["Platinum", 21.45, "color: dodgerblue"]
    ]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1,    { calc: "stringify",        sourceColumn: 1,        type: "string",        role: "annotation" },    2]);

var options = {
    title: "Density of Precious Metals, in g/cm^3",
    width: 600,
    height: 400,
    bar: {groupWidth: "50%"},
    legend: { position: "none" },
};
var chart = new google.visualization.ColumnChart(document.getElementById("columnchart_values"));
chart.draw(view, options);

}

I create a global variable on top of the ts class with the same name(google) and then that variable refer to the required one automatically.(because it is global scope) Then the problem is solved.

declare var google: any;

Solution 15 - Javascript

@d123546 I faced the same issue and got it working now using ngAfterContentInit (Lifecycle Hook) in the component like this :

import { Component, OnInit, AfterContentInit } from '@angular/core';
import { Router } from '@angular/router';
import { ScriptService } from '../../script.service';

@Component({
    selector: 'app-players-list',
    templateUrl: './players-list.component.html',
    styleUrls: ['./players-list.component.css'],
    providers: [ ScriptService ]
})
export class PlayersListComponent implements OnInit, AfterContentInit {

constructor(private router: Router, private script: ScriptService) {
}

ngOnInit() {
}

ngAfterContentInit() {
    this.script.load('filepicker', 'rangeSlider').then(data => {
    console.log('script loaded ', data);
    }).catch(error => console.log(error));
}

Solution 16 - Javascript

I find this solution much cleaner, first import HttpClientJsonpModule in your module and then do something like this

this.apiLoaded = this.httpClient.jsonp(environment.AnyApiUrl, 'callback')
  .pipe(
    map(() => true),
    catchError(() => of(false)),
  );

in your template:

<app-component *ngIf="apiLoaded | async"></app-component>

This solution is in official Angular Google Maps' docs here.

Solution 17 - Javascript

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();
});

Solution 18 - Javascript

import { Injectable } from '@angular/core';
import * as $ from 'jquery';

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 };
            }
        });

        const 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) {
        debugger;
        loadOnce = loadOnce || false;

        scripts.forEach((script: string) => {
            if (!this._scripts[script]) {
                this._scripts[script] = { src: script, loaded: false };
            }
        });

        const 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) {
        debugger;
        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
                const 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 });
            }
        });
    }

    reloadOnSessionChange() {
        window.addEventListener('storage', function(data) {
            if (data['key'] === 'token' && data['oldValue'] == null && data['newValue']) {
                document.location.reload();
            }
        });
    }
}

Solution 19 - Javascript

This solution worked for me :

1 ) create a new class named URLLoader

export class URLLoader {
  constructor() {

  }

  loadScripts() {

    const dynamicScripts = [
      'URL 1',
      'URL 2',
      'URL n'
    ];

    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('app-root')[0].appendChild(node);
    }
  }

}

2 ) extend the class URLLoader and invoke loadScripts method from the component class

export class AppComponent extends URLLoader implements OnInit {  

   constructor(){}

   ngOnInit() {
   super.loadScripts();
   }

}

Solution 20 - Javascript

Angular has the logic to prevent users directly interfere with the html output. So you have to let Angular to inject the

Solution 21 - Javascript

You can use Google Tag Manager to manage your external scripts without going into code. That s a perfect solution for non-tech users and tech users.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCallMeLaNNView Question on Stackoverflow
Solution 1 - JavascriptRahul KumarView Answer on Stackoverflow
Solution 2 - Javascriptdrew mooreView Answer on Stackoverflow
Solution 3 - Javascriptng-darrenView Answer on Stackoverflow
Solution 4 - JavascriptVadim GremyachevView Answer on Stackoverflow
Solution 5 - JavascriptJoelView Answer on Stackoverflow
Solution 6 - JavascriptAswin SanakanView Answer on Stackoverflow
Solution 7 - JavascriptHetdevView Answer on Stackoverflow
Solution 8 - JavascriptEduardo VargasView Answer on Stackoverflow
Solution 9 - Javascript申君健View Answer on Stackoverflow
Solution 10 - Javascriptrobert kingView Answer on Stackoverflow
Solution 11 - Javascriptbob.mazzoView Answer on Stackoverflow
Solution 12 - JavascriptZ3nkView Answer on Stackoverflow
Solution 13 - JavascriptF.H.View Answer on Stackoverflow
Solution 14 - Javascriptshalitha anuradhaView Answer on Stackoverflow
Solution 15 - JavascriptWaseemView Answer on Stackoverflow
Solution 16 - JavascriptazerafatiView Answer on Stackoverflow
Solution 17 - Javascriptunos baghaiiView Answer on Stackoverflow
Solution 18 - JavascriptAniketView Answer on Stackoverflow
Solution 19 - JavascriptAnis KCHAOUView Answer on Stackoverflow
Solution 20 - JavascriptotsiliView Answer on Stackoverflow
Solution 21 - JavascriptSatyam DorvilleView Answer on Stackoverflow