Lazy loading in angular 1+2 hybrid apps - javascript

We have an angular 1+2 hybrid application (therefore using an angular 1 base app).
We are using upgrade adapter to downgrade our angular2 components before we bootstrap our application with the adapter. That works as expected.
However, we anticipate having large number of angular2 components (150+) so loading all the components before bootstrapping would mean a very slow initial load. I am trying to find ways to lazy load angular2 components so that we can load them as needed. Is there any way to achieve that?
Here's part of my code.
main.ts
import baseRouter from './lib/routing/baseRouter';
import router from './lib/routing/router'
import futureRoutes from './futureRoutes'
import { Adapter } from './lib/framework/upgradeAdapter';
import { Http, Headers, Response } from '#angular/http';
import { DashboardComponent } from './2x/Dashboard/dashboard.component';
var app = angular.module('myApp', [
'ui.router',
'ngStorage'
]);
app.config(router(app, futureRoutes))
.config(baseRouter)
.directive('dashboard', Adapter.downgradeNg2Component(DashboardComponent));
Adapter.bootstrap(document.body, ['myApp'], { strictDi: true });
export default app;
module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { DashboardComponent } from '../../2x/Dashboard/dashboard.component';
#NgModule({
imports: [BrowserModule],
declarations: [DashboardComponent]
})
export class AppModule { }
upgradeAdapter.ts
import { UpgradeAdapter } from '#angular/upgrade';
import { AppModule } from './module'
export const Adapter = new UpgradeAdapter(AppModule);
dashboard.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'dashboard',
templateUrl: '/dist/core/2x/Dashboard/dashboard.html',
})
export class DashboardComponent {
greeting: string;
constructor() {
this.greeting = 'Hello world';
}
}
Upon doing this, my dashboard component is available to use in the application.

Related

Bootstrap multiple root component in Angular 4

We've a JQuery application where we've a requirement to implement some modules in Angular 4. So to do that we are manually bootstrapping an Angular app. But now the case is we have created multiple angular component and now they all loading when we bootstrap AppComponent which is making application slow in loading.
So I want to bootstrap multiple root component (i.e. AppComponent, App1Component) so that and will use child components accordingly based on it.
So following is my implementation which is not working.
main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule,App1Module } from './app.module';
import { enableProdMode } from '#angular/core';
platformBrowserDynamic().bootstrapModule(AppModule)
platformBrowserDynamic().bootstrapModule(App1Module)
app.module.ts
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations'
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { AppugComponent } from './appug.component';
import { AppChild1Component } from './profile/appchild1.component';
import { AppChild2Component } from './profile/appchild2.component';
import { AppChild3Component } from './profile/appchild3.component';
import { AppChild4Component } from './profile/appchild4.component';
import { UgChild1Component } from './ug/ugchild1.component';
import { UgChild2Component } from './ug/ugchild2.component';
import { UgChild3Component } from './ug/ugchild3.component';
import { UgChild4Component } from './ug/ugchild4.component';
#NgModule({
imports: [BrowserAnimationsModule, BrowserModule, FormsModule,HttpModule],
declarations: [
AppComponent,
AppChild1Component,
AppChild2Component,
AppChild3Component,
AppChild4Component,
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
#NgModule({
imports: [BrowserAnimationsModule, BrowserModule, FormsModule,HttpModule],
declarations: [
AppugComponent,
UgChild1Component,
UgChild2Component,
UgChild3Component,
UgChild4Component,
],
bootstrap: [ AppugComponent ]
})
export class App1Module { }
app.component.ts
import { Component, OnInit, ChangeDetectorRef } from '#angular/core';
#Component({
selector: 'my-app,
template:`<h1>app</h1>`,
})
export class AppComponent implements OnInit {}
appug.component.ts
import { Component, OnInit, ChangeDetectorRef } from '#angular/core';
#Component({
selector: 'my-appug,
template:`<h1>appug</h1>`,
})
export class AppugComponent implements OnInit {}
Following is the error I'm getting on console:
Unhandled Promise rejection: The selector "my-app" did not match any elements ; Zone: <root> ; Task: Promise.then ; Value: Error: The selector "my-app" did not match any elements
Tried referencing this as well but doesn't working
Any help would be appreciated.
Well I've solved myself by just doing some configuration in main.ts and tsconfig.json
Step 1: Create your module and declare root components which you want to load when you bootstrap that module.
Ex. Here I've created user.module.ts
import { NgModule } from '#angular/core';
// root component of usermodule
import { UserAppComponent } from './userapp.component';
#NgModule({
imports:[FormsModule,HttpModule],
declarations:[UserAppComponent],
providers:[],
bootstrap:[UserAppComponent]
})
export class UserModule { }
Step 2: Go to main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
import { UserModule } from './user.module';
window.platform = platformBrowserDynamic();
window.AppModule = AppModule;
window.UserModule = UserModule;
Step 3: Go to tsconfig.json and insert your newly created module and component in "files" array
"files":[
//....your other components ...//
"myapp/user.module.ts",
"myapp/userapp.component.ts",
]
Step 4: Now you are ready to bootstrap angular module wherever you want from your .js file. Like I've bootstrap like this from my .js file. Bootstrapping may differ based on your requirement but step 1 to 3 should be same.
window.platform.bootstrapModule(window.UserModule);

Angular 1 and Angular 2 Hybrid Application Routing Issue (angular component not displaying)

I have an Angular 1 and Angular 2 hybrid application that was set-up using the following guides, Upgrading from AngularJS and Migrating Angular 1 Application to Angular 2. My root component looks like this:
import { NgModule, Component } from '#angular/core';
import { RouterModule, UrlHandlingStrategy } from '#angular/router';
import { BrowserModule } from '#angular/platform-browser';
import { UpgradeModule } from '#angular/upgrade/static';
import { RouterUpgradeInitializer } from '#angular/router/upgrade';
import { MyModule } from './Mymodule/my-module';
export class Ng1Ng2UrlHandlingStrategy implements UrlHandlingStrategy {
shouldProcessUrl(url: any) {
return url.toString().startsWith("/Mymodule");
}
extract(url: any) {
return url;
}
merge(url: any, whole: any) {
return url;
}
}
#Component({
selector: 'root-component',
template: `
<router-outlet></router-outlet>
<div class="ng-view"></div>
`
})
export class RootComponent { }
#NgModule({
imports: [
BrowserModule,
UpgradeModule,
MyModule,
RouterModule.forRoot([])
],
providers: [
{ provide: UrlHandlingStrategy, useClass: Ng1Ng2UrlHandlingStrategy }
],
bootstrap: [RootComponent],
declarations: [RootComponent]
})
export class Ng2AppModule {
constructor(public upgrade: UpgradeModule) { }
}
And my "main.ts" is the following:
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { setUpLocationSync } from '#angular/router/upgrade';
import { Ng2AppModule } from "./Angular2/app.rootcomponent";
// This is the entry point for the AngularJS/Angular hybrid application.
// It bootstraps the Angular module 'Ng2AppModule', which in turn bootstraps
// the AngularJS module 'angular1App'.
platformBrowserDynamic().bootstrapModule(Ng2AppModule).then(ref => {
const upgrade = (<any>ref.instance).upgrade;
// bootstrap angular1
upgrade.bootstrap(document.body, ['angular1App']);
setUpLocationSync(upgrade);
});
The module 'MyModule' follows:
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { TestDataListComponent } from './testdata-list.component';
#NgModule({
imports: [
RouterModule.forChild([
{
path: 'Mymodule', children: [
{ path: 'testdata', component: TestDataListComponent }
]
}
])
],
declarations: [TestDataListComponent ]
})
export class MyModule {
}
And 'TestDataListComponent' component is very simple:
import { Component } from '#angular/core';
#Component({
selector: 'test-data',
templateUrl: 'App/Angular2/MyModule/testdata-list.component'.html'
})
export class TestDataListComponent{
}
The way I am linking to the Angular 2 component is in a main menu HTML page. The relevant code is the following:
<li id="main-menu" class="menu-top-level" ng-mouseover="cur = 'mymodule'">
<a ng-reflect-router-link="/Mymodule/testdata" href="#/Mymodule/testdata">
MyModule
<span>
<i class="fa fa-check-square fa-2x"></i>
</span>
</a>
</li>
The problem I am experiencing is that clicking on the link above takes me to a blank view, i.e. the component TestDataListComponent is not displayed. However if I replace the following line in my main Angular 2 module, i.e. Ng2AppModule:
RouterModule.forRoot([])
with:
RouterModule.forRoot([], { useHash: true, initialNavigation: false })
component TestDataListComponent shows up fine, but then when I attempt to navigate back to an Angular 1 component, by clicking on a link, the page is blank and what I noticed is that the URL in my browser window looks like this:
http://localhost:60813/#/
while it should looks like this:
http://localhost:60813/#/myclients
If I click on the link a second time, the URL is correct and the Angular 1 component is displayed fine.
The relevant portion of my Angular 1 module angular1App is:
angular.module("angular1App",
["ngRoute",
"myInterceptorService",
"ngStorage",
"ngAnimate",
"ui.bootstrap",
"ngResource",
"SignalR",
"ui.select",
"ngSanitize"])
.config([
"$routeProvider", "$httpProvider", function($routeProvider, $httpProvider) {
$httpProvider.interceptors.push("myInterceptorService");
$routeProvider
.when('/myclients',
{
title: "Client Data",
controller: "clientDataCtrl",
templateUrl: "/App/Common/Views/clientData.html"
})
What is the problem here? Why is either my Angular 2 or Angular 1 component now showing up?
Your problem with component appears to be here:
import { Component } from '#angular/core';
#Component({
selector: 'test-data',
templateUrl: 'App/Angular2/MyModule/testdata-list.component'.html'
})
export class TestDataListComponent{
}
You need to add correct templateUrl strin
The solution was provided by brandonroberts on the Angular github. For details, see this issue https://github.com/angular/angular/issues/18832
Excerpt from solution: "The way setupLocationSync provides the URL to the router for navigating doesn't work correctly with hash-based routing. What I did was tweak the source from the setupLocationSync to pass the URL from the hash to navigate with. This way the Router will handle navigating both scenarios correctly."
See the Plunker in the issue above for details.

Angular2 Unexpected value in Service. Please add annotation

In my Angular2 app am getting the following error Error: (SystemJS) Unexpected value 'ReleasesService' declared by the module 'AppModule'. Please add a #Pipe/#Directive/#Component annotation.
My AppModule:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { routing } from './app.routes';
import { HttpModule } from '#angular/http';
import { SearchFilter } from '../app/search-filter.pipe';
import { ReleasesService } from '../app/releases/releases.service';
import { AppComponent } from './app.component';
import { HomeComponent } from '../app/home/home.component';
import { ReleasesComponent } from '../app/releases/releases.component';
import { DistroComponent } from '../app/distro/distro.component';
import { ContactComponent } from '../app/contact/contact.component';
#NgModule({
imports: [ BrowserModule, HttpModule, routing ],
declarations: [ AppComponent,
SearchFilter,
HomeComponent,
ReleasesComponent,
ReleasesService,
DistroComponent,
ContactComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
My ReleasesService:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { IRelease } from './release';
import 'rxjs/add/operator/map';
#Injectable()
export class ReleasesService {
getReleases() {
return IRelease;
}
}
How to fix it? I reinstalled the Quickstarter (the base for my App), and having the same error when try to create the service.
declarations is only for declarable classes: Components Directives and Pipes
You can add ReleasesService to providers array
#NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
providers: [ ReleasesService ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
See also
https://angular.io/guide/ngmodule-faq#what-classes-should-i-add-to-declarations
I had a similar problem, occurring while a project had angular2 as dependency and a project dependency (with the failing component) as well. Seems like angular2 metadata gets attached to the direct angular2 dependency, so the component in the project dependency wasn't declared in the angular2 of the project.
Workaround is to remove angular2 from the dependency (declaring it as devDependency there) and only use one angular2 instance.
Be sure the decorator has the caracter #.
If you donĀ“t type # before the decorator function you will have this error message
#Component({ selector: '...', }) -> Correct
Component({ selector: '...', }) -> ERROR MESAGE: 'add a #Pipe/#Directive/#component'

Angular 2 templating partial components

Why i have to import all my partial components again in app.module.ts?
Or i'm just doing it wrong?
This is my home component where i'm importing all partial components to add them to Home component.
Home.Component.ts
import { Component } from "#angular/core";
import { SliderComponent } from "./partial/slider/slider.component";
import { AdvanceSearchComponent } from "./partial/advenace-search/advance-search.component";
import { FeatureProfile } from "./partial/feature-profiles/feature-profiles.component";
#Component({
selector: 'app-root',
templateUrl: './Home.component.html'
})
export class HomeComponent{}
This is my app module and here i have to import all partial component again to use them. And my question is why i have to import all Home partial component here when i already include it to my home.component.ts why i don't just add them to declarations and just import HomeComponent
app.module.ts
import { HomeComponent } from './Home/Home.component';
import { SliderComponent } from "./Home/partial/slider/slider.component";
import { AdvanceSearchComponent } from "./Home/partial/advenace- search/advance-search.component";
import { FeatureProfile } from "./Home/partial/feature-profiles/feature-profiles.component";
import { ExploreComponent } from './Explore_spaces/Explore.component';
import { SpaceComponent } from './Space/Space.component';
#NgModule({
declarations: [
AppComponent,
HomeComponent,
SliderComponent,
FeatureProfile,
AdvanceSearchComponent.
ExploreComponent,
SpaceComponent
],
})
Starting from the Angular RC5 you can't add components and filters to your component. The place you need to add your components is the module.
If you need to use those components in many different modules, import and export them in the SharedModule(for example), then use this module as an import to your wanted modules.

Understanding Angular2 Dependency Injection in modules

I have written a feature module , and below is the code
app.ticket.service.ts, this is my service which i would like to inject
'use strict';
import { Injectable } from '#angular/core'
Injectable()
export class AppTicketService {
SaveTicket(): string {
return "service saved ticket";
}
}
app.tickets.module.ts, this is my feature module
'use strict';
import { NgModule } from '#angular/core';
import { SharedModule } from '../shared/app.shared.module';
import { AppCreatTicketComponent } from './app.create-ticket.component';
//-- import services
import { AppTicketService } from './app.ticket.service';
//-- import routing
import { ticketRouting } from './app.ticket.routing';
#NgModule({
declarations:[ AppCreatTicketComponent],
imports:[ SharedModule,
ticketRouting],
exports:[],
providers:[AppTicketService]
})
export class TicketsModule { }
app.create-ticket.component.ts , this is my component ,
which belongs to feature module
'use strict';
import { Component , OnInit , Inject} from '#angular/core';
//-- import service
import { AppTicketService } from './app.ticket.service';
#Component({
templateUrl: '/tickets/create'
})
export class AppCreatTicketComponent implements OnInit{
ngOnInit(){}
constructor(public service1 :AppTicketService) {
let test = this.service1.SaveTicket();
}
}
At runtime I am getting:
"Can't resolve all parameters for AppCreatTicketComponent:" error in browser console
What needs to be modified to resolve this issue?
To fix this issue I had to modify constructor paramter in app.create-ticket.component.ts file
Original
constructor(public service1 :AppTicketService)
Modified
constructor(#Inject(AppTicketService) private service1: AppTicketService)
You can find reason for this here

Categories

Resources