Pankaj Parkar
Indian | 30 | Ex MVP | Angular GDE
pankajparkar
Sr. Technology Consultant, Virtusa
pankajparkar
// app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot([]),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// app.component.ts
@Component({
selector: 'sc-root',
template: `
<h1>Hello {{ title }}</h1>
`
})
export class AppComponent {
title = 'Angular';
}
// main.ts
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
AppModule
App
Component
Routing
Browser
Module
Forms
Module
main.ts
(bootstrap)
pankajparkar
pankajparkar
@NgModule({
declarations: [
AppComponent,
AdminComponent,
DashboardComponent,
NavbarComponent,
BarChartComponent,
PieChartComponent,
PieChartComponent,
ProductComponent,
RolesComponent,
RoleDetailsComponent,
],
imports: [
MatToolbarModule,
MatButtonModule,
AppRoutingModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
SharedModule,
...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
},
{
path: 'roles',
children: [{
path: '',
component: RolesComponent,
}, {
path: 'details/:id',
component: RolesDetailsComponent,
}],
},
{
path: 'admin',
component: AdminComponent,
},
{
path: 'product',
component: ProductComponent,
},
{
path: '**',
redirectTo: 'dashboard'
},
];
pankajparkar
@NgModule({
declarations: [
AppComponent
],
imports: [
MatToolbarModule,
MatButtonModule,
AppRoutingModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
SharedModule,
DashboardModule,
ProductModule,
RolesModule,
SharedModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
😄
Still we have to improve
pankajparkar
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
HttpClientModule,
SharedModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () =>
import('./dashboard/dashboard.module')
.then(m => m.DashboardModule),
},
{
path: 'roles',
loadChildren: () =>
import('./roles/roles.module')
.then(m => m.RolesModule),
},
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.module')
.then(m => m.AdminModule),
},
{
path: 'product',
loadChildren: () =>
import('./product/product.module')
.then(m => m.ProductModule),
},
{
path: '**',
redirectTo: 'dashboard'
},
];
@NgModule({
declarations: [],
imports: [
RouterModule.forRoot(routes),
],
exports: [RouterModule],
})
export class AppRoutingModule { }
ng generate component standalone --standalone
@Component({
selector: 'app-standalone',
standalone: true,
imports: [CommonModule], // <-- all imports goes here
templateUrl: './standalone.component.html',
styleUrls: ['./standalone.component.scss']
})
export class StandaloneComponent implements OnInit {
...
}
pankajparkar
pankajparkar
const routes = [
{
path: 'standalone',
component: StandaloneComponent,
},
...
];
pankajparkar
const routes = [
{
path: 'standalone-lazy',
loadComponent: () => import('./components/standalone-lazy.component')
.then(s => s.StandaloneLazyComponent),
},
]
// dashboard.module.ts
const matModules = [
MatGridListModule,
MatCardModule,
];
@NgModule({
imports: [
...matModules,
CommonModule,
DashboardRoutingModule,
SharedModule,
],
declarations: [
DashboardComponent
],
})
export class DashboardModule { }
<!--dashboard.component.html-->
<mat-grid-list cols="2">
<mat-grid-tile>
<mat-card>
<app-bar-chart></app-bar-chart>
</mat-card>
</mat-grid-tile>
<mat-grid-tile>
<mat-card>
<app-bar-chart></app-bar-chart>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
//dashboard.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent {
}
imports: [...],
standalone: true,
// dashboard.routes.ts
const routes = [{
path: '',
component: DashboardComponent
}];
@NgModule({
declarations: [],
imports: [
RouterModule.forChild(routes),
],
exports: [RouterModule],
})
export class DashboardRoutingModule {
}
pankajparkar
export const routes: Routes = [{
path: 'dashboard',
component: DashboardComponent,
}];
// roles.routing.ts
const matModules = [
MatTableModule,
MatCardModule,
MatButtonModule,
MatDividerModule,
];
@NgModule({
declarations: [
RolesComponent,
RoleDetailsComponent
],
imports: [
...matModules,
RolesRoutingModule,
CommonModule,
]
})
export class RolesModule { }
<mat-card>
<mat-card-title>Roles</mat-card-title>
<mat-card-subtitle>
admin can modify roles
</mat-card-subtitle>
<table mat-table [dataSource]="dataSource">
<!-- Position Column -->
<ng-container matColumnDef="position">
...
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
...
</ng-container>
<tr mat-header-row
*matHeaderRowDef="displayedColumns"></tr>
<tr mat-row
*matRowDef="let row; columns: displayedColumns;">
</tr>
</table>
</mat-card>
@Component({
selector: 'app-roles',
templateUrl: './roles.component.html',
styleUrls: ['./roles.component.scss']
})
export class RolesComponent {
private apiService = inject(ApiService);
displayedColumns: string[] = ['id', 'name'];
dataSource: PeriodicElement[] =
this.apiService.getPeriodicElements();
}
imports: [...],
standalone: true,
const routes = [{
path: '',
component: RolesComponent
}, {
path: 'details/:id',
component: RoleDetailsComponent
}];
@NgModule({
declarations: [],
imports: [
RouterModule.forChild(routes),
],
exports: [RouterModule],
})
export class RolesRoutingModule { }
export const routes = [{
path: '',
component: RolesComponent
}, {
path: 'details/:id',
component: RoleDetailsComponent
}];
pankajparkar
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => import('./dashboard/routes').then(
i => i.routes
),
},
{
path: 'roles',
loadChildren: () => import('./roles/routes').then(
i => i.routes
),
},
{
path: 'product',
loadChildren: () => import('./product/routes').then(
i => i.routes
),
},
{
path: '**',
redirectTo: 'dashboard'
},
];
export const routes = [{
path: '',
component: RolesComponent
}, {
path: 'details/:id',
component: RoleDetailsComponent
}];
export default [{
path: '',
component: RolesComponent
}, {
path: 'details/:id',
component: RoleDetailsComponent
}];
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => import('./dashboard/routes'),
},
{
path: 'roles',
loadChildren: () => import('./roles/routes'),
},
{
path: 'product',
loadChildren: () => import('./product/routes')
},
{
path: '**',
redirectTo: 'dashboard'
},
];
Standalone
+
Single File Component
pankajparkar
ctd.
Bootstrap app without AppModule using `bootstrapApplication`
import {
bootstrapApplication,
} from '@angular/platform-browser';
bootstrapApplication(
AppComponent, {
providers: []
}
);
ctd.
@NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
],
providers: [],
})
export class AppModule { }
Bootstrap app without AppModule using `bootstrapApplication`
@Component({
selector: 'app-root',
standalone: true, // <- add standalone
imports: [], // <- and imports array
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
}
bootstrapApplication(
AppComponent,
{
providers: [
importProvidersFrom([
BrowserModule,
RouterModule.forRoot(routes),
BrowserAnimationsModule,
])
]
}
)
Collects providers from all NgModules and standalone components, including transitively imported ones.
importProvidersFrom([
BrowserModule,
RouterModule.forRoot(routes),
BrowserAnimationsModule,
HttpClientModule,
]),
pankajparkar
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => import('./dashboard/routes'),
},
{
path: 'roles',
loadChildren: () => import('./roles/routes'),
},
{
path: 'product',
loadChildren: () => import('./product/routes')
},
{
path: '**',
redirectTo: 'dashboard'
},
];
npm i -S weather-widget
@NgModule({
imports: [
...,
// import library NgModule
WeatherWidgetModule,
...
]
})
export class AppModule { }
<sc-weather-widget
[city]="cityDetails">
</sc-weather-widget>
@NgModule({
imports: [
...,
// import component directly
WeatherWidgetComponent,
...
]
})
export class DashboardComponent { }
pankajparkar
pankajparkar
HttpModule => provideHttpClient()
RouterModule => providerRouter()
CommonMdoule => NgIf, NgForOf, NgSwitch, etc.
bootstrapApplication(AppComponent)
.then((ref) => {
const wc = createCustomElement(
HelloComponent, {
injector: ref['injector'],
}
);
});
pankajparkar
// get a hand on the environment injector
const app = await createApplication({
providers: [
/* your global providers here */
],
});
// create a constructor of a custom element
const NgElementCtor = createCustomElement(TestStandaloneCmp, {
injector: app.injector
});
// register in a browser
customElements.define('test-standalone-cmp', NgElementCtor);
Ref - https://github.com/angular/angular/pull/46475
pankajparkar
{
provide: ENVIRONMENT_INITIALIZER,
useValue: (fooService: FooService) => {
fooService.initialize();
},
deps: [FooService]
},
pankajparkar
import {
EditEmployeePage as NewEditEmployeePage,
} from './components/employees/edit-employee';
import { EditEmployeePage } from './employees/edit-employee';
...
provideRouter([
{
path: 'edit-employee/:id',
component: NewEditEmployeePage,
canMatch: () => inject(FeatureFlagService).isNewEditEmployeePageEnabled
},
{
path: 'edit-employee/:id',
component: EditEmployeePage
}
])
@Component(...)
export Class AutocompleteComponent {
...
}
@NgModule({
imports: [
CommonModule,
...
],
declarations: [
AutocompleteComponent
],
exports: [AutocompleteComponent],
})
export Class AutocompleteModule {
...
}
Demo - https://github.com/pankajparkar/sc-with-optional-ngmodule
pankajparkar
pankajparkar
https://pankajparkar.dev
pankajparkar
pankajparkar
pankajparkar
https://blog.angular.io/angular-v14-is-now-available-391a6db736af
https://netbasal.com/handling-page-titles-in-angular-40b53823af4a
https://blog.angular.io/angular-extended-diagnostics-53e2fa19ece9
https://marmicode.io/blog/angular-inject-and-injection-functions
https://nartc.me/blog/inheritance-angular-inject
https://netbasal.com/getting-to-know-the-environment-initializer-injection-token-in-angular-9622cb824f57
https://github.com/angular/angular/pull/46475
pankajparkar
By Pankaj Parkar
Standalone Component with Optional NgModule