New features and Dig into Standalone
Components
In a nutshell
Communities
Social Developer
Recognitions
Product Manager @Microsoft
First GDE,MCT and MVP from SL
Top stackoverflow contributor
@sajeetharan
@kokkisajee
@sajeetharan
@sajeetharan
A framework for web front-end app
A platform for integrated development
An ecosystem for developers
open issues
2016
Future ready
$scope
ng-if
ng-app
ng-model
mobile
oriented
better
performance
x11
Angular 1.x vs Angular
Stable and performant
Language service && Tooling
Meet Developers where they are
Smaller, faster, easier
Ivy Everywhere
Image Optimized Directive
Inject API
Developer diagnostics
/ CLI improvements
(ng completion/ ng cache)
Standalone Components
Page Title Strategy
Strictly Typed Forms
kokkisajee
userForm = new FormGroup({
name: new FormControl(''),
age: new FormControl(''),
address: new FormGroup({
city: new FormControl(),
state: new FormControl(),
postalCode: new FormControl(),
}),
});
userForm = new FormGroup({
name: new FormControl<string>(''),
age: new FormControl<number | null>(null),
address: new FormGroup({
city: new FormControl<string>(''),
state: new FormControl<string>(''),
postalCode: new FormControl<number | null>(null),
}),
});
Route Level (hard coded)
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
title: 'Dashboard',
},
{
path: 'typed-forms',
component: TypedFormsComponent,
title: 'Typed Forms'
},
{
path: 'standalone-component',
component: StandaloneComponent,
title: 'Standalone Component',
},
...
];
kokkisajee
Reference: https://nartc.me/blog/inheritance-angular-inject
It takes an instance of dependency from the current injector tree
@Component(...)
abstract class TestComponent {
constructor(
private a: A
) { }
}
@Component(...)
abstract class TestComponent {
a = Inject(A); // <- ✅
}
@Component(...)
abstract class TestComponent {
a: A|undefined;
constructor() {
this.a = inject(A); // <- ✅
}
}
@Component(...)
abstract class TestComponent {
a: A|undefined;
ngOnInit() {
this.a = inject(A); // <- ❌
}
}
kokkisajee
{
"angularCompilerOptions": {
"extendedDiagnostics": {
// The categories to use for specific diagnostics.
"checks": {
// Maps check name to its category.
"invalidBananaInBox": "error"
"nullishCoalescingNotNullable": "error"
},
// The category to use for any diagnostics
// not listed in `checks` above.
"defaultCategory": "suppress"
},
...
},
...
}
kokkisajee
npm install -g @angular/cli
// Installing Angular CLI
ng new my-app
// Creating a new Angular App
ng serve
// Starting local server
kokkisajee
// 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));
Hello
kokkisajee
AppModule
App
Component
Routing
Browser
Module
Forms
Module
main.ts
(bootstrap)
kokkisajee
Building Blocks of Angular
kokkisajee
kokkisajee
DEVFEST is a Angular App - > These volunteers are the components
Hospitality
Speakers
Registration
Speakers
kokkisajee
Hospitality
Registration
Speakers
kokkisajee
Flutter
Golang
Github
@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'
},
];
kokkisajee
@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 { }
kokkisajee
@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
kokkisajee
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 {
...
}
kokkisajee
kokkisajee
const routes = [
{
path: 'standalone',
component: StandaloneComponent,
},
...
];
const routes = [
{
path: 'standalone-lazy',
loadComponent: () => import('./components/standalone-lazy.component')
.then(s => s.StandaloneLazyComponent),
},
]
kokkisajee
// 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,
kokkisajee
Standalone
+
Single File Component
kokkisajee
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
}
])
kokkisajee
kokkisajee
What Devfest has given me
2010
2015
2019
2018
2020
Attended first Devfest SL 2012
Started with angular, became the top angularjs answerer on SO
Became the first google dev expert in the country
Started NG-Srilanka, First Angular Team meet at San Francisco
Book on Angular Projects,Top 4 contributors on Angular
2022
To produce 2 more GDEs from SL
kokkisajee
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
kokkisajee