Skip to content

Angular Quick Reference

A quick lookup for Angular concepts and syntax grouped by category. All examples use the standalone component model (Angular 17+, no NgModules).

@Component({
selector: 'app-card',
standalone: true,
imports: [CommonModule, RouterLink],
templateUrl: './card.component.html',
styleUrl: './card.component.css',
})
export class CardComponent { }
FieldPurpose
selectorCSS selector that identifies this component in templates
standalonetrue — no NgModule needed
importsDirectives, pipes, and other components this template uses
templateUrlExternal HTML template file
templateInline HTML template (alternative to templateUrl)
styleUrlExternal CSS file
@Input() title = '';
@Input({ required: true }) item!: Item;
@Output() selected = new EventEmitter<Item>();
// emit:
this.selected.emit(this.item);
import { signal, computed, effect } from '@angular/core';
count = signal(0);
doubled = computed(() => this.count() * 2);
// Read
this.count() // call it like a function
// Write
this.count.set(5);
this.count.update(n => n + 1);
// Effect (runs when dependencies change)
effect(() => console.log(this.count()));
HookWhen it runs
ngOnInit()Once, after first ngOnChanges — use for initial data fetch
ngOnChanges(changes)When an @Input property changes
ngOnDestroy()Before the component is removed — clean up subscriptions
ngAfterViewInit()After the component’s view is fully initialized

<!-- Interpolation -->
{{ title }}
{{ price | currency }}
<!-- Property binding -->
<img [src]="imageUrl" [alt]="imageAlt" />
<button [disabled]="isLoading">Submit</button>
<!-- Event binding -->
<button (click)="handleClick()">Click</button>
<input (input)="onInput($event)" />
<!-- Two-way binding -->
<input [(ngModel)]="searchTerm" />

Built-in control flow (@if / @for / @switch)

Section titled “Built-in control flow (@if / @for / @switch)”
@if (isLoggedIn) {
<p>Welcome back!</p>
} @else if (isGuest) {
<p>Browsing as guest.</p>
} @else {
<p>Please sign in.</p>
}
@for (item of items; track item.id) {
<li>{{ item.name }}</li>
} @empty {
<li>No items found.</li>
}
@switch (status) {
@case ('loading') { <spinner /> }
@case ('error') { <p>Error loading data.</p> }
@default { <p>{{ status }}</p> }
}

track is required in @for — use a unique identifier like item.id.

<input #searchInput type="text" />
<button (click)="search(searchInput.value)">Search</button>

PipeUsageResult
date{{ date | date:'mediumDate' }}Jun 3, 2026
currency{{ 1200 | currency }}$1,200.00
currency{{ 1200 | currency:'EUR' }}€1,200.00
number{{ 3.14159 | number:'1.0-2' }}3.14
uppercase{{ 'hello' | uppercase }}HELLO
lowercase{{ 'HELLO' | lowercase }}hello
titlecase{{ 'hello world' | titlecase }}Hello World
slice{{ items | slice:0:3 }}first 3 items
json{{ obj | json }}JSON string (useful for debugging)
async{{ obs$ | async }}unwraps Observable/Promise

Chain pipes: {{ price | currency | uppercase }}


import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'detail/:id', component: DetailComponent },
{ path: '**', redirectTo: '' }, // wildcard — must be last
];
{
path: 'browse',
loadComponent: () =>
import('./browse/browse.component').then(m => m.BrowseComponent),
},
<!-- In the root template -->
<router-outlet />
<!-- Navigation links -->
<a routerLink="/">Home</a>
<a [routerLink]="['/detail', item.id]">{{ item.title }}</a>
<a routerLink="/browse" routerLinkActive="active">Browse</a>
import { ActivatedRoute } from '@angular/router';
import { inject } from '@angular/core';
id = inject(ActivatedRoute).snapshot.paramMap.get('id');
// Or subscribe for dynamic changes:
inject(ActivatedRoute).paramMap.subscribe(params => {
this.id = params.get('id');
});
router = inject(Router);
this.router.navigate(['/detail', id]);
this.router.navigateByUrl('/home');
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
export const authGuard: CanActivateFn = () => {
const router = inject(Router);
const authService = inject(AuthService);
return authService.isLoggedIn() ? true : router.createUrlTree(['/login']);
};
// In routes:
{ path: 'watchlist', component: WatchlistComponent, canActivate: [authGuard] }

import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class DataService {
private items: Item[] = [];
getItems(): Item[] {
return this.items;
}
}

providedIn: 'root' makes the service a singleton available app-wide.

// Constructor injection
constructor(private dataService: DataService) { }
// inject() function (preferred in Angular 14+)
dataService = inject(DataService);

import { FormBuilder, Validators } from '@angular/forms';
import { inject } from '@angular/core';
fb = inject(FormBuilder);
form = this.fb.group({
name: ['', [Validators.required, Validators.minLength(2)]],
email: ['', [Validators.required, Validators.email]],
age: [null, Validators.min(18)],
});
// Access
this.form.get('name')?.value
this.form.value // all values as object
this.form.valid // boolean
// Patch values
this.form.patchValue({ name: 'Alice' });
this.form.reset();
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="name" />
@if (form.get('name')?.errors?.['required'] && form.get('name')?.touched) {
<p class="error">Name is required.</p>
}
<button type="submit" [disabled]="form.invalid">Submit</button>
</form>
ValidatorUsage
Validators.requiredField must have a value
Validators.minLength(n)Minimum character count
Validators.maxLength(n)Maximum character count
Validators.emailMust be a valid email format
Validators.min(n)Numeric minimum
Validators.max(n)Numeric maximum
Validators.pattern(regex)Must match regular expression

import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [provideHttpClient()],
};
http = inject(HttpClient);
// GET
this.http.get<Movie[]>('/api/movies').subscribe(movies => {
this.movies = movies;
});
// GET with params
this.http.get<SearchResult>('/api/search', {
params: { q: query, page: '1' },
}).subscribe(result => { ... });
// POST
this.http.post<Item>('/api/items', newItem).subscribe(created => { ... });
// DELETE
this.http.delete(`/api/items/${id}`).subscribe(() => { ... });
import { switchMap, map, catchError, debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { of } from 'rxjs';
// switchMap — cancel previous, switch to new (search, navigation)
searchControl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(q => this.http.get<Result[]>(`/api/search?q=${q}`)),
).subscribe(results => this.results = results);
// map — transform the response
this.http.get<ApiResponse>('/api/data').pipe(
map(res => res.results),
).subscribe(items => this.items = items);
// catchError — handle errors gracefully
this.http.get<Item[]>('/api/items').pipe(
catchError(err => {
console.error(err);
return of([]); // return empty array on error
}),
).subscribe(items => this.items = items);

CommandWhat it does
ng new app-nameScaffold a new Angular project
ng serveStart the dev server (default: localhost:4200)
ng generate component nameGenerate a new component
ng generate service nameGenerate a new service
ng generate guard nameGenerate a route guard
ng buildBuild for production into dist/
ng build --base-href /repo-name/Build with a sub-path base (for GitHub Pages)
ng lintRun the linter
ng testRun unit tests