Angular CheatSheet
Angular CheatSheet
Angualr Forms
Template- Driven forms
Key Features - Use FormModule and ngModel directive - Two-way data binding with [(ngModel)] - Validation attribute in html (required, minlength) - Form state traking : touched, valid, invalid, dirty
Define in template
<form #contactForm="ngForm" (ngSubmit)="OnSubmit(contactForm)">
<input name="name" [(ngModel)]="name" required>
<!-- other field and error we can defiene -->
<button type="submit">Submit</button>
</form>
Usage
- Simple forms with basic validation, Quick response, Forms that mirror data directly, minimal component logic needed
Reactive Forms
Key Features
- Uses
ReactiveFormsModule,FormGroup,FormControl - Programmatic control and validation
- Custom validation:
noSpaceValidatorandabusiveWorldValidator - Better testability and scalability
Example
Template
<form [formGroup]="login" (ngSubmit)="onSubmit()">
<input id="username" formControlName="username">
@if(username.invalid && username.touched){
@if(username.errors?.['required']){
Username is required
}
@if(username.error?.['usernameTaken']){
Username already taken
}
@if(username.hasError('noSpace')){
Name cannot contain space!
}
}
<!-- other fields -->
</form>
Use:
- Complex forms with dynamic validation
- cross-field validation
- Better control over from state
- Easier unit testing
Form Arrays
FormArray is used to manage a dynamic collection of form controls.
Key Features
- Dynamic form controls (add/ remove skills)
- Uses
FormArrayfor collection - Allow user to add/remove filed dynamically Implementation stapes
- in ts file
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, FromControl FormArray, Validators } from '@angular/forms';
@Component({
selector: 'app-profile-editor',
templateUrl: './profile-editor.component.html',
styleUrls: ['./profile-editor.component.css']
})
export class ProfileEditorComponent implements OnInit {
availableSkills = ['C#', 'Jave', 'Angular'];
empFrom = new FormGroup({
name: new FormControl('')
skills: new FormArray([new FormControl('')])
});
// Using FormBuilder
// empForm = this.fb.group({
// name: ['', Validators.required],
// skills: this.fb.array([
// this.fb.control('')
// ])
// });
get skills(){
return this.empForm.get('skills') as FormArray;
// return (<FormArray>this.empForm.get('skills')) as FormArray
}
addSkill(){
this.skills.push(new FormCntrol(''));
// this.skills.push(this.fb.control(''));
}
removeSkill(index: number){
this.skills.RemoveAt(index);
}
onSubmit(){
console.log(this.empForm.value);
}
}
- Bind
FormArrayto template
<form [formGroup]="empForm" (ngSubmit)="onSubmit()">
<input name="name" formControlName="name">
<!-- other form control -->
<div formArrayName="skills">
<button type="button" (click)="AddSkill()">Add Skill</button>
@for(skill of skills.controls; track $index){
<input list ="skillsList" [formControlName]="$index">
<button (click)="removeSkill($index)">Remove Skill</button>
}
<!-- data list for skills -->
<datalist id="skillsList">
@for(skill of availableSkills; track skill){
<option [value]="skill">{{skill}}</option>
}
</datalist>
</div>
</form>
Custom Validators
a custom validator is a function that you define to implement specific validation logic not covered by the built-in validators.
note: we can use custom validators in both tmplate-driven and reactive form as well.
Custom validators for reactive forms
Implementation stapes:
- Create the Validator Function
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
export function abusivewordValidator(control : AbstractControl): ValicationError | null {
const abusivewords = ['idot', 'dumb','fool'];
const controlValue = (control.value as string).toLowerCase();
const containAbusivewords = abusivewords.some(word => controlValue.include(word)
);
return containAbusivewords ? { abusiveword: true }: null;
}
- Add to a Form Control
empFrom = new FormGroup({
name: new FormControl('', Validators.required,abusivewordValidator )
skills: new FormArray([new FormControl('')])
});
// Using FormBuilder
// empForm = this.fb.group({
// name:['', [Validators.required, abusivewordValidator]],
// skills: this.fb.array([
// this.fb.control('')
// ])
// });
Custom validators for Template driven forms
- Create the Validator Directive
ng generate directive shared/abusive-word-validator
- Write Validator function in directive
import { Directive, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn, Validators } from '@angular/forms';
@Directive({
selector: '[appAbusiveWordValidator]',
providers: [{ provide: NG_VALIDATORS, useExisting: AbusiveWordValidatorDirective, multi: true }]
})
export class AbusiveWordValidatorDirective implements Validator {
// Input property to receive the list of abusive words from the template
const abusivewords = ['idot', 'dumb','fool'];
const controlValue = (control.value as string).toLowerCase();
const containAbusivewords = abusivewords.some(word => controlValue.include(word)
);
return containAbusivewords ? { abusiveword: true }: null;
}
- Add the Directive to the Template
<input name="name" [(ngModel)]="name" appAbusiveWordValidator required>
Async Validators
Async validators in Angular are used for validation that requires an asynchronous operation. Async Validators return Promise or Observable and used for server-side validation:
Key Charaterstics:
- Return
Observable<ValidationErrors | null>orPromise<ValidationErrors | null> - Execute AFTER all sync validators pass
- Provide a
pendingstate during validation - Run on value changes with debouncing support
**NOTE: ** - Promises: Single value, not cancellable, simplar for one-time checks - Observable: Multipale value, cancellable(important for preventing race conditions), better for reactive programing with RxJS operators (recommendation).
// Custom async Validators
function userNameAvailable(userService: UserService): AsyncValidatorFn{
return (control: AbstractControl): Observable<ValidationError | null > => {
return userService.checkUserName(control.value).pipe(
map(available => available ? null : {usernameTaken: true}),
catchError(() => of(null))
);
};
}
//Usage
this.form = new FormGroup({
username: new FormControl({
'',
[Validators.required], // sync validators
[usernameAvailableValidator(this.userService)] // Async Validators
})
});
When to use:
- Check if username/email already exists
- Validate data against database
- External API validation (Credit Card verification, Address Verification)
- Any validation required server call (like: Promo code verification, Phonenumber varification).
When NOT to Use:
- Simple formate validation
- Regex pattern (use
Validators.pattern()) - Min/Max length check (use sync validators)
- Required filed validation
Important: Async validators run AFTER sync validators pass.
Note:
- Performance: By default, async validators run on every value change. To avoid excessive API calls (e.g., on every keystroke), you can set the updateOn property to 'blur' or 'submit', or use RxJS operators like
debounceTime(ms),distinctUntillChanged(), switchMap()` check empty value before making API call. UndateOn: 'blur' or 'submit': Validate only when user leaves the field or submit form.username: new FormControl('', { validators: [Validaotrs.required, Valifators.minLength(3)], asyncValidators: [usernameAsyncValidators()], updateOn: 'blur' // Only validate when user leaves the field or // updateOn: 'submit' // Only validate on form submission }) - pending State: While an async validation is in progress, the form control enters a PENDING status. This state can be used in the template to show a loading indicator (e.g., a spinner).
- Signature: An async validator function (implementing the AsyncValidatorFn interface) takes an AbstractControl instance as a parameter and returns an
Observable<ValidationErrors | null>orPromise<ValidationErrors | null>.
Angular Directives
Directive: are maker on a DOM element (such as an attribute, element name, comment, or CSS class) that tell Angular's HTML compiler to attach a spescified behaviour to that element or even transform the DOM element and its children.
Key Charaterstics:
- Extend HTML with new functionally
- Add or modify DOM element behavior
- Can add style, event listners, and attributes
- Reusable across components
- Three types Component, Structural, and Attribute
Classification:
Directives
|- Components (special directives with templates)
|- Structural Directive (modify DOM structure)
|- *ngIf
|- *ngFor
|- *ngSwitch
|-Custom structural directives
|- Attribute Directive (change element behaviour/appearance)
|- Built-in: ngClass, ngStyle, ngModel
|- Custom attribute directive
Type of Directives
Component Directive
A component directive is spacial kind with a trmplate, styling, a component logics.
@Component({
selector: 'app-user',
template: `<div>{{name}}</div>`,
styles: ['div {color: blue}']
})
export class UserComponent {
@Input() name: String;
}
Structural Directives
Modify the DOM structure by adding or removing elements.
<div *ngIf="isVisable">Visible</div>
<!-- ng-template use -->
<div *ngIf="isVisible; thenblock else elseBlock"></div>
<ng-template #thenBolck>Then Block</ng-template>
<ng-template #elseBolck>Else Block</ng-template>
<!-- ngfor -->
<!-- basic -->
<div *ngFor="let item of items">{{item}}</div>
<!-- with index -->
<div *ngfor =" let item of items; let i=index">
<!-- with first, last, odd, even, count -->
<div *ngFor="let item of items; let first=fisrt; let last = last; let odd = odd; let even = even; let count = count ">
<!-- Track by performance -->
<div *ngfor =" let item of items; trackBy: tracByFn">
<!-- for trackBy implement in component
// Without trackBy : Re-renders all items when list changes
// With trackBy: Only re-enders changed items
trackByFn(index: number, item: User): number {
return item.id; // Returns unique identifier
}
// Alternative: Using aeeow function
trackByFn = (index: number, item: User) => item.id;
-->
<!-- Angular 15+ :new Syntex -->
<!-- basic @for -->
@for(item of items track; item.id) { }
<!-- index @for -->
@for(item of items track; let i=$index; track item.id) { }
<!-- odd, even @for -->
@for(item of items track; let first=$first; let last=$last track user.id) { }
<!-- Empaty state with @Empty -->
@for(item of items track; item.id) {
} @Empty{
<p>No item is available</p>
}
<!-- ngSwitch -->
<div [ngSwitch]="status">
<div *ngSwitchCase="'active'">
<div *ngSwitchDefault>
<!-- ngTemplateOutlate -> Randers a template dynamically-->
<ng-container *ngTemplateOutlate="haderTemplate"></ng-container>
<ng-container *ngTemplateOutlate="contentTemplate"></ng-container>
<ng-template #haderTemplate>Hraders Template</ng-template>
<ng-template #contentTemplate>Content Template</ng-template>
Note: Benefits of TrackBy:
- Improve perfomance with large lists
- Prevents re-rendering unchange items
- Maintains forms state and focus
Attribute Directives
Modify the appearance or behavior of DOM elements without changing structure.
<div [ngClass]="{ active: isActive }">
<div [ngStyle]="{color: dynamicColor}">
<input [(ngModel)]="name">
difference in ngClass and class Binding
| ngClass | class Binding |
|---|---|
| Multiple class at once | Single class binding |
| Conditional class assignment | Direct property binding |
| Can accept object, string, or array | Simple syntex |
When to use
ngClass: Multiple condition classesClass binding: Single class or static classes
Custom Directives
Creating Custom Attribute Directives
Key Concept:
- Implement @Directive decorator
- Use @Input for properties
- Use ElementRef to access element
- Use Randerer2 for safe DOM manipulation
Step 1: Generate directives
ng generate directive directives/highlight
#or
ng g d directives/highlight
Step 2: Implemetnt Custom directive
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]', // Attribute selector: use as <p appHighlight>
standalone: true // Directives are standalone by default in modern Angular
})
export class HighlightDirective {
// Define an input property to allow specifying a custom highlight color
@Input() highlightColor: string = 'yellow';
// Inject ElementRef to access the host element
constructor(private el: ElementRef) {}
// Listen for the mouseenter event on the host element
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.highlightColor);
}
// Listen for the mouseleave event on the host element
@HostListener('mouseleave') onMouseLeave() {
this.highlight(''); // Clear the highlight
}
// Private helper method to apply the style
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
Step 3: Use the Directive in a Component
// In Component
imports: [HighlightDirective], // Add the directive to the imports array
// In Template
<!-- Use the directive with the default yellow color -->
<p appHighlight>Hover over me for default highlight!</p>
<!-- Use the directive and bind an input property for a custom color -->
<p [appHighlight]="favoriteColor">Hover over me for lightblue highlight!</p>
Component/Directive Lifecycle Hook
| Hook | Directive | Component | Purpuse |
|---|---|---|---|
| constructor | ✔ | ✔ | Initialize dependencies |
| ngOnChange | ✔ | ✔ | Detect input change |
| ngOnInit | ✔ | ✔ | Initialize component/directive |
| ngDoCheck | ✔ | ✔ | Custome change detection |
| ngAfterContentInit | ✔ | ✔ | After content initialization |
| ngAfterViewInit | X | ✔ | After view initilazition |
| ngOnDestroy | ✔ | ✔ | Cleanup |
Directive Don't have:
ngAfterViewInit- Directives have no viewngAfterViewChecked- Directives have no view
Angular Pipes
- Pipe are simple functions that accept an input value and return a transformed output value. Key Charaterstics:
- Transform data in templates without changing the original data
- Can be chained together
- Can accept parameters
- Can be pure or impure
- Reusable across the application
Built-in Pipes
Angualr provides several built-in pipes for common transformation:
- DatePipe
- CurrencyPipe
- NumberPipe
- PercentagePipe
- Uppercase/LowerCase/TitleCasePipe
- SlicePipe
- JsonPipe
Custom Pipe
Step 1: Generate Pipe
ng generate pipe pipes/custom-pipe-name
#or
ng g p pipes/custom-pipe-name
Step 2: Implement Pipe logic
import {Pipe, PipeTrasform } from '@angular/core';
@pipe({
name: 'reverse',
standalone: true
})
export class ReversePipe implements Pipetransform {
transform(value: string): string {
if(!value) return value;
return value.split('').reverse().join('');
}
}
Usage
{{ 'Angular' | reverse }}
Pure vs Impure Pipe
PurePipe
Charateristics:
- Called only when Angular detects a pure change to the input value
- Pure changes: primitive value (String, Number, boolean) or object reference
- More performant as they're colled less frequently
- Default behaviour (pure: true)
Example
@pipe({
name: 'purePipe',
pure: true // Default
})
export class AppComponent{
items = ['Apple', 'Banana', 'Cherry'];
addItem(){
// This won't trigger pure pipe (same reference)
this.items.push('Date');
//This will trigger pure pipe (new refrence)
this.items = [...this.item, 'date'];
}
}
Impure Pipes
Charateristics:
- Called on every change detection cycle
- Detects change within objects or array
- Less performent but more responsive to data change
- Must explicitly set pure: false
@pipe({
name: 'purePipe',
pure: false // Impure pipe
})
export class ImpurePipe implements PipeTrasform{
transform(item: any[], searchText: string): any[]{
if(!items || !searchtext) return items;
return items.filter(item =>
item.toLowerCase().includes(searchText.toLowerCase())
);
}
}
When to Use Impure Pipe
- Filtering/ Sorting dynamic array
- Real-time dat transformation
- When we need to detech changes within object/arrays
Async Pipe
This Async Pipe is a spacial built-in pipe that subscribes to Observables or Promises and return the letest value.
Key Benifits
- Automatic subscription Management: Automattically scubscribe and Unsubscribe
- Memory Leak Preventation: Prevent memory leaks
- Cleaner Code: No need for manual subscription in component
Observable Example:
// Component
//Observable that emit every second
time$: Observable<Date> = interval(1000).pipe(
map(()=> new Date())
);
//Template
// <h3> Current Time: {{time$ | async | date: 'medium'}}
//Observable form Http call
user$: Observable<User> = this.http.get<User>('/api/user');
constructor(private http: HttpClient ){}
//Template
// <h3> USer: {{user$ | async | json }}
Promise Example
// Component
dataPromise: Promise<string>;
constructor(){
this.dataPromise = this.fatchData();
}
fatchData(): Promise<string>{
return new Promise((resolve)=> {
setTimeout(()=> resolve('Data loaded!'), 2000);
});
}
// Template
<div>{{dtaPromise | async }} </div>
Pipe Life Cycle
- Construction
- Transform method calls
- Destruction
OnPush OnPush change detection strategy is a performance optimization that instructs Angular to skip checking a component (and its children) unless specific triggers occur.
import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector: 'app-on-push-demo',
templateUrl: './on-push-demo.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent { }
Comunication Method in Angular
Type of Communication
| Type | Direction | Use Case |
|---|---|---|
| @Input | Parent -> Child | Pass sata down the component tree |
| @Output | Child -> Parent | Emit events up the component tree |
| Service | Any -> Any | Shared data accross components |
| ViewChild | Parent -> Child Template | Direct DOM/Component access |
| Template Ref Variables | Template | Local template access |
| Subject | Any <-> Any | Complex state management |
@Input - Passing data ot Child component (one way data binding)
// Child component ts
import { Component, Input } from '@angular/core';
@Input() message: string ='';
// Input with alias
@Input('message') data: any;
// Required input (Angular 16+)
@Input({ required: true }) title: string;
// parent component ts
ParentMessage =' Hello from Parent';
<app-child [message]="ParentMessage"></app-child>
@Output - Emitting Events from Child t Parent.
//child component ts
import { Component, Output, EventEmitter} from '@angular/core';
@Output() messageEvent = new EventEmitter<string>();
sentMesage(){
this.messageEvent.emit('Hello from child!');
}
//Parent component
receivedMessage (message: string){
console.log(message);
}
<app-child (messageEvent)="receivedMessage($event)">
ViewChild/ViewChildren/ContentChild/ContentChildren
These decorater allow perent component to access child component instances or DOM elements directly.
ViewChild - Single Child Reference
// parent component ts
//-------------------------------
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child-component';
@ViewChild('ChildComponent') child!: ChildComponent;
// OR by template reference variable:
//@ViewChild('ChildRef') childRef!: ChildComponent;
ngAfterViewInit(){
//child is now available
console.log(this.child.message); // output: Hello from the child!
}
callChildMethod() {
this.child.updateMessage('Message updated by parent!');
}
// parent template
//---------------------
<app-child></app-child>
// or
//<app-child #ChildRef></app-child>
// Child Component ts
//--------------------------------
message = 'Hello from the child!';
public updateMessage(newMessage: string) {
this.message = newMessage;
}
Key Points:
@ViewChildis available afterngAfterViewInit()- Use for direct child components in the template.
- Single reference only.
ViewChildren - Multiple Child References
// Parent Template html
<app-child *ngFor="let item of items" #children></app-child>
// Parent component ts
import { AfterViewInit, Component, QueryList, ViewChildren } from '@angular/core';
import { ChildComponent } from './child.component';
@ViewChildren('children') children!: QueryList<ChildComponent>;
ngAfterViewInit() {
// Access and interact with each child component
this.children.forEach(child => {
console.log(child); // Access properties or call methods
// child.someMethod();
});
// Subscribe to changes in the list of children
this.children.changes.subscribe((newList: QueryList<ChildComponent>) => {
console.log('Children list updated:', newList.toArray());
});
}
ContentChild - Access Projected component
Used to access child component/elements that are projected via <ng-content>.
@ContentChild (or its signal-based equivalent, contentChild()) is a decorator used to access the first matching element, component, or directive that has been projected into a component using the
//1. Parent Component- The parent component provides the content to be projected.
// app.component.html
//------------------------------------
<app-container>
<app-header><app-header>
</app-container>
// or
//<app-container #headerRef>
// <app-header><app-header>
// </app-container>
//2. Child Component (Container) - The child component uses <ng-content> to display the projected content and @ContentChild to access it in its TypeScript class.
// container.component.ts
//-------------------------------------
import { AfterContentInit, ContentChild, ElementRef, Component } from '@angular/core';
@Component({
selector: 'app-container',
template: `
<div class="container">
<ng-content></ng-content> <!-- Projection slot -->
</div>
`,
})
export class ContainerComponent implements AfterContentInit {
@ContentChild('HeaderComponent') header!: HeaderComponent;
// Query for the element with the template reference variable '#headerRef'
// @ContentChild('headerRef') projectedHeaderEl!: ElementRef;
ngAfterContentInit() {
// The projected content is available here
if (this.projectedHeaderEl) {
this.heaader.highlight();
//or
// console.log('Projected content text:', this.projectedHeaderEl.nativeElement.textContent);
// You can also manipulate the DOM here, e.g., change style
// this.projectedHeaderEl.nativeElement.style.color = 'blue';
}
}
}
ContentChildren - Multiple Projected items
import { Component, ContentChildren, QueryList} from '@angular/core';
import { TabComponent } from './tab.component';
@Component({
selector: 'app-tab-group',
template: `
<div class="tab">
<ng-content></ng-content>
</div>
`
})
export class TabGroupComponent implements AfterContentInit {
@ContentChildren(TabComponent) tabs!: QueryList<TabComponent>;
AfterContentInit(){
this.tab.forEach((tab, index) => {
tab.id = index;
});
}
}
Comparison Table
| Decorator | Target | When Available | Usage |
|---|---|---|---|
| ViewChild | Direct child in Template | AfterViewInit | Single refrence |
| ViewChildren | Multiple direct children | AfterViewInit | QueryList |
| ContentChild | Projected content child | AfterContentInit | Single reference |
| ContentChildren | Multiple projected children | AfterContentInit | QueryList |
Template Reference variables
Template reference variables allow to refrence DOM elements or components in the template.
//Basic usage
//-----------------------
//app component html
<input #nameInput type="text">
<button (click)="onSubmit(nameInput.value)">Submit</button>
// app component ts
onSubmit(value: string){
console.log(value);
}
//Getting Dom Element Reference
//-----------------------
//app component html
<input #nameElement type="text">
<button (click)="focusInput()">Focus Input</button>
// app component ts
import { ViewChild, ElementRef } from '@angular/core';
@ViewChild('nameElement') inputElement! = ElementRef<HTMLInputElement>;
focusInput() {
this.inputElement.nevigateElement.focus();
}
// Template ref with ng-template
//-------------------------------------
//app component html
<div *ngIf="!isloading; else loadingTemplate">
<ng-template #loadingTemplate>
<p>Loading....</p>
</ng-template>
Event Emitter vs Subjects
Both are used for event-driven communication, but they have different use cases and characteristics.
EventEmitter
EventEmitter is a subclass of subject specifically designed for component outputs.
Charaterstics:
- Part of
@angular/core - Meant for
@Output()decoretors - Synchronous by default
- Limited API comared to Subject
Subject
Subject is RxJS class that act as bot an observable and observer.
Type
- Subject:- No Initial value
- BehaviourSubject: - Has initial value
- ReplaySubject: - Buffer Values
- AsyncSubject: - Emits value on Complate
| Feature | EventEmitter | Subject |
|---|---|---|
| Use case | @Output decorator | Service-based communication |
| Memory Effcient | Yes | Depends on type |
| Complate on unsubscribe | yes | No |
| Can Complate | yes | yes |
| RxJs operator | Limited | Full RxJS Suport |
| Asnyc capability | No | Yes(with async operation) |
Angular Dependency Injection
DI is a design pattern where a class receives its dependencies from external source rather then creating them itself. Angular's DI framework provides dependencies to class upon instantiation.
- Makes code more testable ( can inject mocks)
- Promotes loose coupling
- Enables singleton pattern for service
- Simplify component code
- Makes dependencies explicit and manageable.
Benifits:
- Testability: Easy to mock demendencies in unit tests
- Maintainability: Loose coupling b/w components
- Reusability: Service can be shared accross the application.
- Flexiblility: Easy to swap implementations
DI is differ from manual dependency injection as below:
- Automatic: framework handles instantiation and injection
- Hierarchical: Multi-level injector tree
- Declarative: Use decorators (@Injectable, Inject)
- Optimized: Tree-shakeable and laz-loadable
- Type-safe: Leverages Typescript types as tokens
Manual DI requires explicit instatiation and passing of dependencies.
Hierarchical Injector System
a core part of its Dependency Injection (DI) mechanism, creating a tree of injectors that mirrors the application's component tree.
Tree Structure: Every component instance can have its own injector, which is a child of its parent component's injector
Injector Hierarchy levels
NullInjector (top) -> throws error if token not found
⇩
PlatformInjector -> Platform level dependencies
⇩
RootInjector (Application/ root) -> Singletons Application wise
⇩
ModuleInjector (lazy-loaded modules) -> Lazy loaded module scope
⇩
ElementInjector (Component/Directive)
⇩
ElementInjector (Child component)
Provider Scopes
1. Root Scope
Singleton accross entire application
@Injectable({ provideIn: 'root' })
charaterstics:
- Tree-shakable ( removed if not used)
- Lazy instantiation (created when first inject)
- Single instance app-wide
when use
- Service manages global state (AuthService, ConfigService)
- Service should be singleton (HttpClient, Logger) -Service used accross multiple features
- want tree-shaking benfits
2. Platform Scope
Shared accross multiple Angular application on the same page
@Injectable({ provideIn: 'platform' })
Use case: Rare, typically for microfrontends.
3. Module Scope
Singleton within module
//Eager-loaded module
@NgModule({
provides: [ModuleService]
})
// or using priovdeIn
@Injectable({ provideIn: 'FeatureMudle' })
4. Component Scope
New instance per component
@Component({
....
providers: [ComponentService] // New instance
})
constructor(private service : ComponentService){}
When use
- Service manages component specific state
- Need different instance for different component
- Service lifecycle tide to omponent
- want isolation ( FormService for eatch form)
Example:-
- Root: AuthService, HttpClient, GlobalErrorHandler
- Component: FormService, LocalFilterService, WidgetStateService
Comments
Post a Comment