Dynamically load external javascript file from Ang

2019-01-04 12:23发布

I am creating an Angular application using Angular 4 and the CLI. I am trying to add the SkyScanner search widget into one of my components.

Skyscanner Widget Example

Part of the implementation requires the addition of a new external script:

<script src="https://widgets.skyscanner.net/widget-server/js/loader.js" async></script>

I am not sure of the correct way to reference this file. If I add the script into my index.html file, the widget doesn't load unless a full page refresh is performed. I assume the script tries to manipulate the DOM on load and the elements don't exist when the script runs.

What is the correct way to load the script only when the component containing the Skyscanner widget is loaded?

7条回答
虎瘦雄心在
2楼-- · 2019-01-04 12:48

Note: This is specially for external js links! Step 1. Add your angular script into the index.html file at the bottom of your body is recommended! I tried all other ways but failed.

<!-- File Name: index.html and its inside src dir-->

<body class="">
  <app-root></app-root>

    <!-- Icons -->
        <script src="https://unpkg.com/feather-icons/dist/feather.min.js"></script>

</body>

Next there are two ways to do this... In Anguar5 use inside your component folder at the top type in this code

declare var feather:any;

and then inside your class call the method you need. For example

//FileName: dashboard.component.ts
import { Component, OnInit } from '@angular/core';
declare var feather:any;
export class DashboardComponent implements OnInit{
    ngOnInit(){
        feather.replace();
    }
}

and this should run your code! The other way which might work in older version. I have not checked!

//FileName: dashboard.component.ts
import { Component, OnInit } from '@angular/core';

export class DashboardComponent implements OnInit{

     ngOnInit(){
    
    
        let node = document.createElement('script');
        node.innerText='feather.replace()';
        node.type = 'text/javascript';
        node.async = false;
        node.charset = 'utf-8';
        
        document.getElementsByTagName('body')[0].appendChild(node);
    
    }

}

If you are not getting my code then also give try to this link too.

Hope this helps!

查看更多
家丑人穷心不美
3楼-- · 2019-01-04 12:51

add loader.js to your assets folder then in your angular-cli.json

"scripts": ["./src/assets/loader.js",]

then add this to your typings.d.ts

 declare var skyscanner:any;

and you will be able to use it

  skyscanner.load("snippets","2");
查看更多
女痞
4楼-- · 2019-01-04 12:54

Try to load external JavaScript on component load as below :

loadAPI: Promise<any>;

constructor() {        
    this.loadAPI = new Promise((resolve) => {
        this.loadScript();
        resolve(true);
    });
}

public loadScript() {        
    var isFound = false;
    var scripts = document.getElementsByTagName("script")
    for (var i = 0; i < scripts.length; ++i) {
        if (scripts[i].getAttribute('src') != null && scripts[i].getAttribute('src').includes("loader")) {
            isFound = true;
        }
    }

    if (!isFound) {
        var dynamicScripts = ["https://widgets.skyscanner.net/widget-server/js/loader.js"];

        for (var i = 0; i < dynamicScripts .length; i++) {
            let 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);
        }

    }
}
查看更多
女痞
5楼-- · 2019-01-04 12:58

You can create your own directive to load script as below

import { Directive, OnInit, Input } from '@angular/core';

@Directive({
    selector: '[appLoadScript]'
})
export class LoadScriptDirective implements OnInit{

    @Input('script') param:  any;

    ngOnInit() {
        let node = document.createElement('script');
        node.src = this.param;
        node.type = 'text/javascript';
        node.async = false;
        node.charset = 'utf-8';
        document.getElementsByTagName('head')[0].appendChild(node);
    }

}

And you can use it anywhere in your components template as below

<i appLoadScript  [script]="'script_file_path'"></i>

For example, to dynamically load JQuery in your component, insert below code in your component's template

<i appLoadScript  [script]="'/assets/baker/js/jquery.min.js'"></i>
查看更多
淡お忘
6楼-- · 2019-01-04 13:03

I have done this code snippet

 addJsToElement(src: string): HTMLScriptElement {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    this.elementRef.nativeElement.appendChild(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');
}

EDIT: With new renderer Api it can be written like this

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

StackBlitz

查看更多
爷、活的狠高调
7楼-- · 2019-01-04 13:06

I had the same problem, but in my case, I was importing 10 libraries at the end of the html file, and these libraries have a lot of methods, listeners, events, and more, and in my case I didn't need to call a method specifically.

The example about what I had:

<!-- app.component.html -->

<div> 
 ...
</div>

<script src="http://www.some-library.com/library.js">
<script src="../assets/js/my-library.js"> <!-- a route in my angular project -->

As mentioned, it didn't work. Then, I find somehing that helped me: Milad response

  1. Remove the script calls in the app.component.html. You have to link these scripts in the app.component.ts file.

  2. In ngOnInit(), use a method to append the libraries, for example:

``

<!-- app.component.ts -->

export class AppComponent implements OnInit {
   title = 'app';
   ngOnInit() {
     this.loadScript('http://www.some-library.com/library.js');
     this.loadScript('../assets/js/my-library.js');
   }
  }

  public loadScript(url: string) {
    const body = <HTMLDivElement> document.body;
    const script = document.createElement('script');
    script.innerHTML = '';
    script.src = url;
    script.async = false;
    script.defer = true;
    body.appendChild(script);
  }
}

It functions for me. I use Angular 6, hope it helps.

查看更多
登录 后发表回答