Pankaj Parkar
Indian | 30 | Ex MVP | Angular GDE
pankajparkar
Sr. Technology Consultant, Virtusa
pankajparkar
@Component({
selector: 'app-typed-forms',
templateUrl: './typed-forms.component.html',
styleUrls: ['./typed-forms.component.css'],
})
export class TypedFormsComponent {
userForm = new FormGroup({
name: new FormControl(''),
age: new FormControl(''),
address: new FormGroup({
city: new FormControl(),
state: new FormControl(),
postalCode: new FormControl(),
}),
});
ngOnInit() {
const value = this.userForm.value;
const { name, age, addres } = value;
const { city, state, postalCode } = addres;
}
}
type UserForm {
name: string;
age: string;
address: {
city: string;
state: string;
postalCode: string;
}
}
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),
}),
});
userForm = new FormGroup({
name: new FormControl(''),
age: new FormControl(''),
address: new FormGroup({
city: new FormControl(),
state: new FormControl(),
postalCode: new FormControl(),
}),
});
interface Address {
city?: FormControl<string>;
state?: FormControl<string>;
postalCode?: FormControl<string>;
}
interface UserForm {
name?: FormControl<string>;
age?: FormControl<string>;
address?: FormGroup<Address>;
}
userForm = new FormGroup<UserForm>({
name: new FormControl(),
age: new FormControl(),
address: new FormGroup<Address>({
city: new FormControl(),
state: new FormControl(),
postalCode: new FormControl(),
}),
});
submit() {
console.log(this.userForm.value);
const { address, age, name } = this.userForm.value;
}
userForm = new UntypedFormGroup({
name: new UntypedFormControl(''),
age: new UntypedFormControl(''),
address: new UntypedFormGroup({
city: new UntypedFormControl(),
state: new UntypedFormControl(),
postalCode: new UntypedFormControl(),
}),
});
(developer preview)
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
.
.
.
Root
Component
// app.module.ts
@NgModule({
declarations: [
AppComponent,
...
],
bootstrap: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
...
],
providers: [],
})
export class AppModule { }
// main.ts
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
C
P
S
D
M
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,
AppRoutingModule,
BrowserAnimationsModule,
])
]
}
)
ctd.
const routes = [
{
path: 'standalone',
component: StandaloneComponent,
},
];
const routes = [
{
path: 'standalone-lazy',
loadComponent: () => import('./components/standalone-lazy.component')
.then(s => s.StandaloneLazyComponent),
},
]
pankajparkar
ctd.
const routes = [{
path: 'standalone-childrens',
loadComponent: () => import('./components/standalone-childrens.component')
.then(s => s.StandaloneChildrenComponent),
children: [
{
path: 'child-firstchild',
component: import('./components/standalone-first-child.component')
.then(s => s.FirstChildComponent)
},
{
path: 'child-firstchild',
component: import('./components/standalone-first-child.component')
.then(s => s.FirstChildComponent)
},
]
}]
Lazy Standalone Component and its children routes
pankajparkar
pankajparkar
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',
},
...
];
pankajparkar
Route Level (dynamic)
@Injectable({ providedIn: 'root' })
export class DynamicTitleService implements Resolve<string> {
constructor() { }
async resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const post = await fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json());
return post.title;
}
}
pankajparkar
[
{
path: 'dashboard',
component: DashboardComponent,
title: DynamicTitleService
},
...
]
Global App Level strategy
@Injectable({ providedIn: 'root' })
export class TitleStrategyService extends TitleStrategy {
constructor(private readonly title: Title) {
super();
}
override updateTitle(routerState: RouterStateSnapshot) {
const title = this.buildTitle(routerState);
if (title !== undefined) {
this.title.setTitle(`Angular 14 | ${title}`);
}
}
}
pankajparkar
{
provide: TitleStrategy,
useClass: TitleStrategyService,
}
@Component({
selector: 'app-protected-variable',
template: `
<h1>
Protected: {{ message }}
</h1>
`,
})
export class ProtectedVariableComponent {
protected message = 'My Protected Varaible';
}
pankajparkar
{
"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"
},
...
},
...
}
pankajparkar
this.viewContainerRef.createEmbeddedView(
templateRef,
context,
{ injector }
)
const templateRef = this.template.createEmbeddedView({
$implicit: user
}, { injector });
this.vc.insert(templateRef);
pankajparkar
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); // <- ❌
}
}
Reference: https://nartc.me/blog/inheritance-angular-inject
@Directive()
abstract class Base {
a = inject(A);
}
@Component()
class Cmp extends Base {
constructor(b: B) {
super();
}
}
@Directive()
abstract class BaseClass {
constructor(private a: A) {
}
}
@Component()
class Cmp extends BaseClass {
constructor(b: B, a: A) {
super(a);
}
}
pankajparkar
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div>{{ state.counter }}</div>
<div>
<button (click)="state.counter = 0">RESET</button>
<button (click)="increment()">+</button>
</div>`,
})
export class CounterComponent {
state = injectState({
counter: 0,
});
increment() {
this.state.counter += 1;
}
}
pankajparkar
Blog - https://marmicode.io/blog/angular-inject-and-injection-functions
function injectState() {
/* @hack wrongly assuming that ChangeDetectorRef is a ViewRef
* Yeah! CDR is actually the ViewRef of the component. */
const viewRef = inject(ChangeDetectorRef) as ViewRef;
/* Initialize state. */
const state = new RxState();
state.set(initialState);
queueMicrotask(() =>
viewRef.onDestroy(() => state.ngOnDestroy())
);
}
pankajparkar
Demo - https://github.com/pankajparkar/angular-14
pankajparkar
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
pankajparkar
By Pankaj Parkar
Monorepo with Angular