Whenever a new angular project is created, automatically a root module "AppModule" in file app.module.ts and a root component "AppComponent" in file app.component.ts is provided. Bootstrapping in angular is performed in two stages.
First, main application module originally "AppModule" is bootstrapped via bootstrapModule method of the platform "platformBrowserDynamic()"is used.
main.ts file
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
Second bootstrapping root component in this case "AppComponent" in main application module.
app.module.ts - Contains Root Module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule
],
bootstrap:[AppComponent],
providers: []
})
export class AppModule {}
The component which bootstrap the application is referred by property - "bootstrap: [AppComponent]". When the application runs, angular finds the element in file "index.html" that is the selector of a bootstrapped component in the DOM and initializes the component. This process signifies that we are aware of the component we want to bootstrap the application with. Initially, the application is bootstrapped with root component "AppComponent".
app.component.ts -file containing root or parent component
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularManualBootstrap</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root> //selector of bootstrapped component
</body>
</html>
Sometimes a requirement may arise when bootstrapping the application with a particular component is defined by the server during runtime. This is known as manual bootstrapping.
Consider following example for manual bootstrapping:-
Create two new components Admin Component and User Component. The decision which component is to be used for bootstrapping the application is made at runtime.
admin.component.ts -file containing AdminComponent
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-admin',
template: '<h3>This component is used for application admin.</h3>',
})
export class AdminComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
user.component.ts -file containing UserComponent
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-user',
template:'<h3>This component is used for application user.</h3>'
})
export class UserComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
The app.module.ts file is changed to
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AdminComponent } from './admin/admin.component';
import { UserComponent } from './user/user.component';
@NgModule({
declarations: [
AppComponent,
AdminComponent,
UserComponent
],
imports: [
BrowserModule
],
bootstrap:[],
entryComponents:[
AdminComponent,UserComponent
],
providers: []
})
export class AppModule {}
We can observe that bootstrap property is empty as which component the application will be bootstrapped with will be decided at runtime. Instead, two newly created components are registered within entryComponents property so as to create factories for these components. Previously root component "AppComponent" was not added to entryComponents because angular automatically adds components specified in the bootstrap property to entry components.
The index.html is chaged to
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularManualBootstrap</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<h1 id="componentstatus">
Loading Component content here ... //No selector as it is decided at run time
</h1>
</body>
</html>
When above application runs, following error ocurs.
Above error basically explains that which component to be used for bootstrapping is not specified. We did not specified it because we did not know beforehand which component is to be bootstrapped. To manually bootstrap application, ngDoBoostrap method is to be added to the AppModule class.
export class AppModule {
ngDoBootstrap(app) { }
}
Before going on details of this method, we should know about "ApplicationRef". ApplicationRef is a reference to an angular application which is currently running on the page. So this ApplicationRef is passed to the ngDoBoostrap method and then for bootstrapping, the bootstrap method of the ApplicationRef is used for initializing root component.
The app.module.ts is changed to:-
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AdminComponent } from './admin/admin.component';
import { UserComponent } from './user/user.component';
import { Observable } from "rxjs"
@NgModule({
declarations: [
AppComponent,
AdminComponent,
UserComponent
],
imports: [
BrowserModule
],
entryComponents:[
AdminComponent,UserComponent
],
providers: []
})
export class AppModule {
ngDoBootstrap(app) {
fetchComponentSelector()
.subscribe((name)=>{ bootstrapRootComponent(app, name)});
}
}
// app - running application reference (ApplicationRef)
// name - the component name(selector) to bootstrap
function bootstrapRootComponent(app, name) {
// define the possible bootstrap components with their selectors (html host elements)
const options = {
'app-admin': AdminComponent, //component selector act as key
'app-user': UserComponent
};
// obtain reference to the DOM element and changing it's content
const componentStatusElement = document.querySelector('#componentstatus');
componentStatusElement.textContent = 'Loaded Component';
// DOM element creation for bootstrapped component and finally adding it to DOM
const componentElement = document.createElement(name);
document.body.appendChild(componentElement);
//selected component boostrap the application
const component = options[name];
app.bootstrap(component);
}
//To fetch component selector
function fetchComponentSelector() {
return new Observable((observer) => {
setTimeout(() => { observer.next('app-admin');}, 2000);
});
}
The bootstrapRootComponent function is responsible for bootstrapping selected root component. the fetchComponentSelector function is created to emulate HTTP request to the server and returns a selector within 2 seconds. This function is creating an observable by using the new Observable() call, then subscribed to by an observer, executed by calling the next(). next method just sends data to its subscribers.
When an application runs, ngDoBootstrap method calls a fetchComponentSelector method, subscribing it. the fetchComponentSelector method returns "app-admin" selector making AdminComponent a root component and bootstrapping the application with it.
Output :-
Changing the selector in fetchComponentSelector to "app-user" will change root component to UserComponent and application will be bootstrapped with it.
Output :
0 Comment(s)