Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using external javascript libraries in angular 2 lazy loaded module, not index.html

So I want to include an external JS library, a carousel slider in the is case, to my Angular 2 app. I have seen a lot of tutorials that show how it can be added I have done that successfully, but referencing the library on index.html.

This as you will know, will load the library every time the app is visited, regardless of whether they visit the components needing the carousel. Since it's pretty hefty, I only want to load it where it is needed, which is inside a lazy loaded module.

I haven't tried, but I'm sure I could just chuck the script tag in the component that uses it, but this doesn't feel right to me.

There must be a right way. What is it!?

Thanks!

like image 772
Steve D Avatar asked Mar 04 '17 07:03

Steve D


People also ask

How do you do lazy loading in Angular 2?

To lazy load Angular modules, use loadChildren (instead of component ) in your AppRoutingModule routes configuration as follows. content_copy const routes: Routes = [ { path: 'items', loadChildren: () => import('./items/items. module'). then(m => m.

Can I use JavaScript libraries in Angular?

To use the JavaScript library in an Angular project, install the library via npm and check for its type declaration file. Install the type declaration file from @types/<library-name>, if it is not a part of the source code. import the library in your component and start using it.

How do you use a lazy load module without routing?

define where we want to load our component in the template with the ng-template tag, define its view query through ViewChild decorator, which gives us access to the DOM and defines the container to which the component will be added, finally, dynamic import the component and add it to the container.

Can you lazy load JavaScript?

Currently, lazy loading is natively supported on the web for most modern and updated browsers. However, for browsers that don't offer this support yet, polyfills or libraries that implement this technique provide simple API layers above them.


2 Answers

We are doing this in one of our projects to load js libraries dynamically

ScriptStore.ts that 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 Script {

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));
like image 120
Rahul Kumar Avatar answered Nov 08 '22 00:11

Rahul Kumar


It really depends on the type of the library you are trying to load and what is the module loader you are using on your application.

I'm going to assume you are using Typescript or at least ES6 syntax.

If your 3rd party dependency is a AMD/UMD/CommonJS module

In this case, on top of you component file you can just import it.

import {SomeClassName} from "path/to/library";

If your 3rd party is a global module (ex: JQuery plugin)

In this case you just need to import the js file and it will be available on a global variable.

import "path/to/library";

Conclusion

In any case, you should check if the 3rd party library has already typings available, that will help you if you are using Typescript.

Depending on your module loader, you may need to make some configurations prior to this. But without more information is hard to help you.

Best, jpsfs

like image 21
jpsfs Avatar answered Nov 08 '22 02:11

jpsfs