最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Make Angular 2 component download and run a script - Stack Overflow

programmeradmin0浏览0评论

I am trying to use MathJax to display equations in my Angular 2 app. Only a small bit of my app actually needs this functionality, so I don't want all users to have to download the 3-400kb needed.

My initial thought was to import "mathjax" within my ponent, so that the library will be loaded only when the ponent is created. However, I learned from my earlier question that MathJax doesn't play well with others because it uses its own custom module loader.

My current setup loads the script from my index.html but that means everyone will download it when only a small percentage of users need this ponent

<script src=".js?config=AM_SVG"></script>

Is there a clean way in Angular 2 to have my ponent download a script within the ngOnInit() hook and execute a callback once it's in the DOM? Something such as (pseudo-code):

ngOnInit(){
    //download script, add to DOM      
    fetch('https://...MathJax.js').then(addToDom).then(this.onMathJaxLoaded);
}
onMathJaxLoaded(){
  // Run math renderer
  MathJax.Hub.Queue("Typeset",...);
}

I am trying to use MathJax to display equations in my Angular 2 app. Only a small bit of my app actually needs this functionality, so I don't want all users to have to download the 3-400kb needed.

My initial thought was to import "mathjax" within my ponent, so that the library will be loaded only when the ponent is created. However, I learned from my earlier question that MathJax doesn't play well with others because it uses its own custom module loader.

My current setup loads the script from my index.html but that means everyone will download it when only a small percentage of users need this ponent

<script src="https://cdn.mathjax/mathjax/latest/MathJax.js?config=AM_SVG"></script>

Is there a clean way in Angular 2 to have my ponent download a script within the ngOnInit() hook and execute a callback once it's in the DOM? Something such as (pseudo-code):

ngOnInit(){
    //download script, add to DOM      
    fetch('https://...MathJax.js').then(addToDom).then(this.onMathJaxLoaded);
}
onMathJaxLoaded(){
  // Run math renderer
  MathJax.Hub.Queue("Typeset",...);
}
Share Improve this question edited May 23, 2017 at 11:54 CommunityBot 11 silver badge asked Dec 6, 2016 at 9:37 BeetleJuiceBeetleJuice 41k22 gold badges118 silver badges181 bronze badges 3
  • Might be a option to inject a <script> tag into your DOM.. stackoverflow./questions/16230886/… – TryingToImprove Commented Dec 6, 2016 at 9:39
  • Note from the future: cdn.mathjax is nearing its end-of-life, check mathjax/cdn-shutting-down for migration tips. – Peter Krautzberger Commented Apr 11, 2017 at 15:35
  • @PeterKrautzberger Thanks for the note – BeetleJuice Commented Apr 22, 2017 at 5:24
Add a ment  | 

2 Answers 2

Reset to default 6

I have not tried it, but I think this might be possible:

ngOnInit(){
    //download script, add to DOM      
    var script = document.createElement('script');
    document.body.appendChild(script)
    script.onload = this.onMathJaxLoaded.bind(this);
    script.src = 'https://...MathJax.js';
}
onMathJaxLoaded(){
  // Run math renderer
  MathJax.Hub.Queue("Typeset",...);
}

Here is a fiddle, which contains a example of how it would work in plain JavaScript; https://jsfiddle/5qu5h7bc/

Building on @TryingToImprove's solution, I decided to add a ScriptLoaderService to my app with a load() function that fetches a remote script and notifies the caller (using an RxJS Observable) when it's done.

Here is how to use it:

this.scriptLoaderService.load('https://...js').subscribe(
    ()=>console.log('script has loaded');
);

Here is the service:

/**
 * A directory of scripts that have been or are being loaded
 */
private scripts = new Map<string,Observable<boolean>|boolean>();

/**
 * Downloads script; returns Observable that emits TRUE once "load" event fires
 */
public load(src:string):Observable<boolean>{        
    if(this.scripts.has(src)){
        // If script has already been fully loaded.
        if(this.scripts.get(src)===true) return Observable.of(true);

        // Else if download is already underway but load event hasn't fired yet
        else return this.scripts.get(src);
    }

    //Add a script tag to the DOM
    let script = document.createElement('script');
    document.body.appendChild(script);

    // upon subscription, listen for the load event. Once it arrives, emit TRUE
    let obs:Observable<boolean> = Observable.fromEvent(script,'load')
        // Map should hold TRUE once script is loaded
        .do(()=> this.scripts.set(src,true))
        .take(1).map(e=>true);

    // set the src attribute (will cause browser to download)
    script.src = src;

    //add observable to the scripts Map
    this.scripts.set(src,obs);

    return obs;
}

Tested on Firefox 51

发布评论

评论列表(0)

  1. 暂无评论