Dynamic Script Loading in Angular: A Solution Introduction: In Angular applications, the need to include external scripts can arise. However, adding tags directly to index.html and relying on ES6 import statements has limitations. This article presents a technique to dynamically load scripts based on user configuration, allowing developers to choose between CDN or local script sources.</p> <p><strong>Dynamic Script Loading:</strong></p> <p>To dynamically load scripts, we can employ the following steps:</p> <ol> <li> <strong>Create a Script Store:</strong> Establish an array of objects called ScriptStore, which holds script paths and unique names for dynamic loading.</li> <li> <strong>Inject the Script Service:</strong> Implement the ScriptService as an injectable Angular service that manages script loading.</li> <li> <strong>Load Scripts Method:</strong> Define a load method in ScriptService to load scripts dynamically. This method takes script names as parameters and returns a promise.</li> <li> <strong>Load Script Implementation:</strong> Within the load method, check if the script is already loaded. If not, create a <script> element, specify its source, and handle events for script loading (e.g., onload or onreadystatechange).</li> <li> <strong>Inject and Invoke the Service:</strong> Inject ScriptService into the component or service where you need to load scripts. Call the load method to load the desired scripts.</li> </ol> <p><strong>Example Code:</strong></p> <p>Below is a sample implementation of the script store and service:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre>interface Scripts { name: string; src: string; } // Script store with sample script definitions export const ScriptStore: Scripts[] = [ { name: 'filepicker', src: 'https://api.filestackapi.com/filestack.js' }, { name: 'rangeSlider', src: '../../../assets/js/ion.rangeSlider.min.js' } ]; @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) => { // Check if script is already loaded if (this.scripts[name].loaded) { resolve({ script: name, loaded: true, status: 'Already Loaded' }); } else { let 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) => resolve({ script: name, loaded: false, status: 'Loaded' }); document.getElementsByTagName('head')[0].appendChild(script); } }); } }</pre><div class="contentsignin">Copy after login</div></div> <p><strong>Usage:</strong></p> <p>In the component or service where you wish to load scripts dynamically, inject the ScriptService. Then, within a method, invoke the load method like this:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre>this.script.load('filepicker', 'rangeSlider').then(data => { console.log('script loaded ', data); }).catch(error => console.log(error));</pre><div class="contentsignin">Copy after login</div></div> <p>In this example, both filepicker and rangeSlider scripts will be loaded dynamically. You can now configure the ScriptStore to load scripts from either a CDN or a local folder as needed.</p>