I have been doing R&D over a bug in angular(not calling it a bug). But In SPA, js loses its scope after routing to a different component. I have read almost every answer available on the internet. Let me put it out in a simpler manner what the problem is.
- Scope ends after we route to a different element(we are using external js)
- Since my js are interconnected, it all had to load at once. so loading a particular js through component.ts method is not feasible as it again changes the scope of DOM and the other features stop working.
so if anyone is encountering such issues, let's discuss here.
My CODE : Script-loader.ts
import { Injectable } from '@angular/core'; @Injectable({
providedIn: 'root' }) export class ScriptLoaderService {private scripts: any = {}; load(...scripts: string[]) { this.scripts = scripts; let promises: any[] = []; scripts.forEach((script) => promises.push(this.loadScript(script))); return Promise.all(promises); } loadScript(name: string) { return new Promise((resolve, reject) => { let script = (document.createElement('script') as any); script.type = 'text/javascript'; script.src = name; script.async = false; script.defer = false; if (script.readyState) { //IE script.onreadystatechange = () => { if (script.readyState === 'loaded' || script.readyState === 'complete') { script.onreadystatechange = null; resolve({script: name, loaded: true, status: 'Loaded'}); } }; } else { //Others script.onload = () => { resolve({script: name, loaded: true, status: 'Loaded'}); }; } script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'}); document.getElementsByTagName('head')[0].appendChild(script); }); }
} Blockquote
blogs.component.ts
import { Component, OnInit, AfterViewInit } from '@angular/core'; import { ScriptLoaderService } from '../script-loader.service'; declare var $: any;
@Component({ selector: 'app-blogs', templateUrl: './blogs.component.html', styleUrls: ['./blogs.component.css'] }) export class BlogsComponent implements OnInit, AfterViewInit {
constructor(private scriptloader: ScriptLoaderService) { }
ngAfterViewInit(): void { this.scriptloader.load( 'assets/js/app.js', 'assets/data/tipuedrop_content.js', 'assets/js/global.js', 'assets/js/navbar-v1.js', 'assets/js/main.js', 'assets/js/widgets.js',
'assets/js/lightbox.js', 'assets/js/feed.js', ); }
ngOnInit(): void { }
}
Blogs.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from "@angular/router"; import { BlogsComponent } from './blogs.component';
const routes: Routes = [ { path: "", component: BlogsComponent } ];
@NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class BlogsModule { }
videos.component.ts
import { Component, OnInit, AfterViewInit } from '@angular/core'; import { ScriptLoaderService } from '../script-loader.service'; declare var $: any; @Component({ selector: 'app-videos',
templateUrl: './videos.component.html', styleUrls: ['./videos.component.css'] }) export class VideosComponent implements OnInit, AfterViewInit {constructor(private scriptloader: ScriptLoaderService) { }
ngAfterViewInit(): void { this.scriptloader.load( 'assets/js/app.js', 'assets/data/tipuedrop_content.js', 'assets/js/global.js', 'assets/js/navbar-v1.js', 'assets/js/main.js','assets/js/widgets.js', 'assets/js/lightbox.js', 'assets/js/feed.js', ); }
ngOnInit(): void { }
}
videos.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from "@angular/router"; import { VideosComponent } from './videos.component';
const routes: Routes = [ { path: "", component: VideosComponent } ];
@NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class VideosModule { }
App-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PreloadingStrategy,
PreloadAllModules } from "@angular/router"; import { BlogsModule } from './blogs/blogs.module'; import { FeedModule } from './feed/feed.module'; import { HangoutModule } from './hangout/hangout.module'; import { HomeModule } from './home/home.module'; import { VideosModule } from './videos/videos.module';const routes: Routes = [
{ path:"feed", loadChildren: "./feed/feed.module#FeedModule" }, { path:"read", loadChildren: "./blogs/blogs.module#BlogsModule" }, { path:"watch", loadChildren: "./videos/videos.module#VideosModule" }, { path:'home', loadChildren:"./home/home.module#HomeModule" }, { path:"hangout", loadChildren:"./hangout/hangout.module#HangoutModule" }
];
@NgModule({ imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })], exports: [RouterModule] }) export class AppRoutingModule { }
Now what is happening that when I am routing from blogs to videos. It is adding all the js below previous ones again. I don't know if it is a good practice or not. Here is the DOM HEAD to show what's happening