import { Component, Input, Output, EventEmitter } from '@angular/core';
// Basic component
@Component({
selector: 'app-greeting',
standalone: true,
template: `<h1>Hello, {{ name }}!</h1>`
})
export class GreetingComponent {
@Input() name: string = '';
}
// Component with inputs and outputs
@Component({
selector: 'app-button',
standalone: true,
template: `
<button (click)="handleClick()">{{ text }}</button>
`
})
export class ButtonComponent {
@Input() text: string = 'Click me';
@Output() clicked = new EventEmitter<void>();
handleClick() {
this.clicked.emit();
}
}
// Component with external template
@Component({
selector: 'app-card',
standalone: true,
templateUrl: './card.component.html',
styleUrls: ['./card.component.css']
})
export class CardComponent {
@Input() title: string = '';
}
<!-- Interpolation -->
<p>{{ message }}</p>
<p>{{ user.name }}</p>
<p>{{ getValue() }}</p>
<!-- Property binding -->
<img [src]="imageUrl" [alt]="imageAlt">
<button [disabled]="isDisabled">Click</button>
<div [class.active]="isActive"></div>
<div [style.color]="textColor"></div>
<!-- Event binding -->
<button (click)="handleClick()">Click</button>
<input (input)="onInput($event)">
<form (submit)="onSubmit($event)">
<!-- Two-way binding -->
<input [(ngModel)]="name">
<!-- Template reference -->
<input #nameInput>
<button (click)="logValue(nameInput.value)">Log</button>
<!-- @if -->
@if (isLoggedIn) {
<app-dashboard />
} @else if (isLoading) {
<app-spinner />
} @else {
<app-login />
}
<!-- @for -->
@for (item of items; track item.id) {
<div>{{ item.name }}</div>
} @empty {
<p>No items found</p>
}
<!-- @switch -->
@switch (status) {
@case ('active') {
<span class="active">Active</span>
}
@case ('inactive') {
<span class="inactive">Inactive</span>
}
@default {
<span>Unknown</span>
}
}
<!-- @defer (lazy loading) -->
@defer (on viewport) {
<app-heavy-component />
} @placeholder {
<p>Loading...</p>
}
<!-- *ngIf -->
<div *ngIf="isVisible">Visible</div>
<div *ngIf="user; else noUser">{{ user.name }}</div>
<ng-template #noUser><p>No user</p></ng-template>
<!-- *ngFor -->
<li *ngFor="let item of items; let i = index; trackBy: trackById">
{{ i }}: {{ item.name }}
</li>
<!-- *ngSwitch -->
<div [ngSwitch]="status">
<p *ngSwitchCase="'active'">Active</p>
<p *ngSwitchCase="'inactive'">Inactive</p>
<p *ngSwitchDefault>Unknown</p>
</div>
<!-- ngClass and ngStyle -->
<div [ngClass]="{ 'active': isActive, 'disabled': isDisabled }"></div>
<div [ngStyle]="{ 'color': textColor, 'font-size': fontSize + 'px' }"></div>
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// Injectable service
@Injectable({
providedIn: 'root'
})
export class UserService {
private http = inject(HttpClient);
private apiUrl = '/api/users';
getUsers() {
return this.http.get<User[]>(this.apiUrl);
}
getUser(id: number) {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}
createUser(user: User) {
return this.http.post<User>(this.apiUrl, user);
}
}
// Using service in component
@Component({
selector: 'app-users',
standalone: true,
template: `...`
})
export class UsersComponent {
private userService = inject(UserService);
users: User[] = [];
ngOnInit() {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
}
import { Component, signal, computed, effect } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<p>Count: {{ count() }}</p>
<p>Double: {{ doubleCount() }}</p>
<button (click)="increment()">+</button>
`
})
export class CounterComponent {
// Writable signal
count = signal(0);
// Computed signal
doubleCount = computed(() => this.count() * 2);
constructor() {
// Effect runs when signals change
effect(() => {
console.log('Count changed:', this.count());
});
}
increment() {
this.count.update(c => c + 1);
// Or: this.count.set(this.count() + 1);
}
}
import {
Component, OnInit, OnDestroy, OnChanges,
AfterViewInit, SimpleChanges
} from '@angular/core';
@Component({
selector: 'app-lifecycle',
standalone: true,
template: `<p>{{ message }}</p>`
})
export class LifecycleComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
@Input() data: string = '';
message: string = '';
// Called when input properties change
ngOnChanges(changes: SimpleChanges) {
console.log('Changes:', changes);
}
// Called once after first ngOnChanges
ngOnInit() {
console.log('Component initialized');
}
// Called after view is initialized
ngAfterViewInit() {
console.log('View initialized');
}
// Called before component is destroyed
ngOnDestroy() {
console.log('Component destroyed');
// Clean up subscriptions, etc.
}
}
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-form',
standalone: true,
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<input formControlName="name" placeholder="Name">
@if (form.get('name')?.invalid && form.get('name')?.touched) {
<span class="error">Name is required</span>
}
<input formControlName="email" placeholder="Email">
<button type="submit" [disabled]="form.invalid">Submit</button>
</form>
`
})
export class FormComponent {
form = new FormGroup({
name: new FormControl('', [Validators.required, Validators.minLength(3)]),
email: new FormControl('', [Validators.required, Validators.email])
});
onSubmit() {
if (this.form.valid) {
console.log(this.form.value);
}
}
}
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable, catchError, map } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class ApiService {
private http = inject(HttpClient);
// GET request
getData(): Observable<Data[]> {
return this.http.get<Data[]>('/api/data');
}
// GET with params
search(term: string): Observable<Data[]> {
const params = new HttpParams().set('q', term);
return this.http.get<Data[]>('/api/search', { params });
}
// POST request
create(data: Data): Observable<Data> {
return this.http.post<Data>('/api/data', data);
}
// With headers
getWithAuth(): Observable<Data> {
const headers = new HttpHeaders().set('Authorization', 'Bearer token');
return this.http.get<Data>('/api/protected', { headers });
}
// With error handling
getDataSafe(): Observable<Data[]> {
return this.http.get<Data[]>('/api/data').pipe(
map(response => response),
catchError(error => {
console.error('Error:', error);
throw error;
})
);
}
}
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'users/:id', component: UserDetailComponent },
{
path: 'admin',
loadComponent: () => import('./admin/admin.component')
.then(m => m.AdminComponent),
canActivate: [AuthGuard]
},
{ path: '**', component: NotFoundComponent }
];
// Using router in component
import { Component, inject } from '@angular/core';
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
@Component({
selector: 'app-nav',
standalone: true,
imports: [RouterLink],
template: `
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
<a [routerLink]="['/users', userId]">User</a>
<button (click)="navigate()">Go to About</button>
`
})
export class NavComponent {
private router = inject(Router);
private route = inject(ActivatedRoute);
userId = 1;
navigate() {
this.router.navigate(['/about']);
}
ngOnInit() {
// Get route params
this.route.params.subscribe(params => {
console.log(params['id']);
});
// Get query params
this.route.queryParams.subscribe(params => {
console.log(params['search']);
});
}
}
// Built-in pipes
// In template:
{{ value | uppercase }}
{{ value | lowercase }}
{{ date | date:'short' }}
{{ date | date:'yyyy-MM-dd' }}
{{ price | currency:'USD' }}
{{ value | number:'1.2-2' }}
{{ object | json }}
{{ items | slice:0:5 }}
{{ observable$ | async }}
// Custom pipe
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number = 50): string {
if (value.length <= limit) return value;
return value.substring(0, limit) + '...';
}
}
// Usage: {{ longText | truncate:100 }}
// card.component.ts
@Component({
selector: 'app-card',
standalone: true,
template: `
<div class="card">
<div class="header">
<ng-content select="[card-header]"></ng-content>
</div>
<div class="body">
<ng-content></ng-content>
</div>
<div class="footer">
<ng-content select="[card-footer]"></ng-content>
</div>
</div>
`
})
export class CardComponent {}
// Usage
// <app-card>
// <h2 card-header>Title</h2>
// <p>Main content goes here</p>
// <button card-footer>Action</button>
// </app-card>
import { Component, ViewChild, ViewChildren, ElementRef, QueryList, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-example',
standalone: true,
template: `
<input #nameInput>
<app-child #childComponent></app-child>
<div #item *ngFor="let i of items">{{ i }}</div>
`
})
export class ExampleComponent implements AfterViewInit {
@ViewChild('nameInput') inputRef!: ElementRef<HTMLInputElement>;
@ViewChild('childComponent') child!: ChildComponent;
@ViewChildren('item') items!: QueryList<ElementRef>;
ngAfterViewInit() {
this.inputRef.nativeElement.focus();
this.child.someMethod();
this.items.forEach(item => console.log(item.nativeElement));
}
}