All authors

Claude Skills by HoangNguyen0403
github.com/HoangNguyen04031,434 skills30 installs1,975 views
- Angular ComponentsPrefer `toSignal()` for an observable consumed by the template. It subscribes in the component's injection context and automatically unsubscribes when the component is destroyed. ```ts import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; @Component({ selector: 'app-user-feed', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: ` @for (user of users(); track user.id) { <p>{{ use...Votes: 0GitHub stars: 549
- Angular Dependency InjectionUse `inject()` from `@angular/core` to resolve a dependency from the current Angular injection context. The usual location is a class field initializer: ```ts import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class UserService { private readonly http = inject(HttpClient); getUser(id: string) { return this.http.get('/api/users/' + id); } } ``` `inject()` is the constructor-equivalent style recommend...Votes: 0GitHub stars: 549
- Angular Dependency InjectionCreate a typed `InjectionToken` for configuration instead of using a string token or trying to inject a TypeScript interface. Interfaces do not exist at runtime, while an `InjectionToken` is a runtime identity: ```ts // api-config.ts import { InjectionToken } from '@angular/core'; export interface ApiConfig { baseUrl: string; timeoutMs: number; } export const API_CONFIG = new InjectionToken<ApiConfig>('API_CONFIG'); ``` Provide the value in the application configuration: ```ts // app.config.t...Votes: 0GitHub stars: 549
- Angular Dependency InjectionDeclare the service with `@Injectable()` and provide it on the route that owns its lifetime: ```ts // checkout-state.service.ts import { Injectable, inject } from '@angular/core'; import { CartService } from './cart.service'; @Injectable() export class CheckoutState { private readonly cart = inject(CartService); step = 1; nextStep(): void { this.step += 1; } } ``` Register it in the route configuration: ```ts // app.routes.ts import { Routes } from '@angular/router'; import { CheckoutState } ...Votes: 0GitHub stars: 549
- Angular Dependency InjectionFor an authentication service used across the application, make it a tree-shakable root singleton: ```ts // auth.service.ts import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class AuthService { private readonly http = inject(HttpClient); isAuthenticated(): boolean { return Boolean(localStorage.getItem('access_token')); } refreshSession() { return this.http.get('/api/auth/session'); } logout(): void...Votes: 0GitHub stars: 549
- Angular Dependency InjectionIn Angular 19+, register an initializer with `provideAppInitializer()` in the application configuration. The initializer function runs in an injection context, so it can resolve a service with `inject()`: ```ts // config.service.ts import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { firstValueFrom } from 'rxjs'; interface RuntimeConfig { apiUrl: string; } @Injectable({ providedIn: 'root' }) export class ConfigService { private readon...Votes: 0GitHub stars: 549
- Angular Dependency InjectionFor form validators, register each validator with Angular’s `NG_VALIDATORS` token and set `multi: true`. The multi flag makes Angular collect all matching providers into the validator array instead of replacing an earlier provider: ```ts import { Directive, Injectable, InjectionToken } from '@angular/core'; import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn, } from '@angular/forms'; @Injectable() export class NoWhitespaceValidator implements Validator { validate...Votes: 0GitHub stars: 549
- Angular Directives PipesAn attribute directive adds behavior to an existing element. Declare it with a selector in brackets, make it standalone, and put reusable DOM behavior in the directive class. ```ts import { Directive, ElementRef, Renderer2, input } from '@angular/core'; @Directive({ selector: '[appHighlight]', standalone: true, host: { '(mouseenter)': 'highlight()', '(mouseleave)': 'clearHighlight()', }, }) export class HighlightDirective { readonly appHighlight = input('yellow'); constructor( private readonl...Votes: 0GitHub stars: 549
- Angular Directives Pipes`hostDirectives` applies a standalone directive to a component or another directive, so the host gets the behavior without inheritance. Inputs and outputs are private to the host by default; expose the ones that should be part of the host component's API. ```ts import { Component, Directive, input, output } from '@angular/core'; @Directive({ selector: '[appTooltip]', standalone: true, host: { '[attr.title]': 'text()', '[attr.aria-label]': 'text()', '(mouseenter)': 'show()', '(mouseleave)': 'h...Votes: 0GitHub stars: 549
- Angular Directives PipesImplement `PipeTransform` and explicitly mark the pipe as standalone and pure. A pure pipe is evaluated again only when one of its input values changes, which lets Angular cache the result for unchanged inputs. ```ts import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'truncate', standalone: true, pure: true, }) export class TruncatePipe implements PipeTransform { transform(value: string, limit = 50): string { if (value.length <= limit) { return value; } if (limit <= 1) { retur...Votes: 0GitHub stars: 549
- Angular Directives PipesPut host property bindings and host event listeners in the directive decorator's `host` object. This is the preferred declaration style here; do not use `@HostBinding` or `@HostListener` for the same behavior. ```ts import { Directive, input, signal } from '@angular/core'; @Directive({ selector: '[appTooltip]', standalone: true, host: { '[attr.aria-label]': 'text()', '[attr.data-tooltip-visible]': 'visible() ? "true" : "false"', '[class.tooltip-visible]': 'visible()', '(mouseenter)': 'open()'...Votes: 0GitHub stars: 549
- Angular Directives PipesSet `standalone: true` in the `@Directive` metadata. A standalone directive is not declared in an `NgModule`; import it directly into each standalone component (or directive) that uses it. ```ts import { Directive, ElementRef, Renderer2 } from '@angular/core'; @Directive({ selector: '[appFocusRing]', standalone: true, host: { '(focusin)': 'setActive(true)', '(focusout)': 'setActive(false)', }, }) export class FocusRingDirective { constructor( private readonly element: ElementRef<HTMLElement>,...Votes: 0GitHub stars: 549
- Angular Directives PipesCreate a standalone, pure pipe and define the truncation contract in `transform`. The implementation below preserves strings within the limit and counts the ellipsis as the final character. ```ts import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'truncate', standalone: true, pure: true, }) export class TruncatePipe implements PipeTransform { transform(value: string, limit = 50): string { if (limit < 1) { return ''; } return value.length <= limit ? value : `${value.slice(0, li...Votes: 0GitHub stars: 549
- Angular FormsUse Angular Reactive Forms with an explicitly typed `FormGroup` and non-nullable controls. `validators.ts`: ```ts import { AbstractControl, ValidationErrors, ValidatorFn, } from '@angular/forms'; export const blockedEmailValidator: ValidatorFn = ( control: AbstractControl, ): ValidationErrors | null => { const email = String(control.value).toLowerCase(); return email.endsWith('@blocked.example') ? { blockedEmail: true } : null; }; ``` Component: ```ts import { Component, DestroyRef, inject, }...Votes: 0GitHub stars: 549
- Angular FormsUse a standalone `ValidatorFn` in `validators.ts`, then attach it to a strictly typed reactive form. ```ts // validators.ts import { AbstractControl, ValidationErrors, ValidatorFn, } from '@angular/forms'; export function forbiddenName(name: string): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const value = String(control.value ?? '').trim().toLowerCase(); return value === name.toLowerCase() ? { forbiddenName: { value: control.value } } : null; }; } ``` ```ts...Votes: 0GitHub stars: 549
- Angular FormsUse **Reactive Forms** for any non-trivial Angular form. They provide explicit, strictly typed `FormGroup<T>` models, reusable validation, and better control over dynamic or state-driven inputs. Use template-driven forms only for very small, straightforward forms with minimal validation. Recommended pattern: ```ts // validators.ts import { AbstractControl, ValidationErrors } from '@angular/forms'; export function passwordsMatch( control: AbstractControl ): ValidationErrors | null { const { pa...Votes: 0GitHub stars: 549
- Angular FormsUse Angular Reactive Forms with `FormBuilder.nonNullable`: ```ts // profile.component.ts import { Component, inject } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { profileValidator } from './validators'; interface ProfileForm { name: FormControl<string>; email: FormControl<string>; } @Component({ // ... }) export class ProfileComponent { private readonly fb = inject(FormBuild...Votes: 0GitHub stars: 549
- Angular FormsAssuming “signal store” means an `@ngrx/signals` store, use a strictly typed Reactive Form and synchronize it in both directions. `profile.store.ts` ```ts import { patchState, signalStore, withMethods, withState } from '@ngrx/signals'; export type Profile = { name: string; email: string; }; export const ProfileStore = signalStore( { providedIn: 'root' }, withState<{ profile: Profile }>({ profile: { name: '', email: '', }, }), withMethods((store) => ({ updateProfile(profile: Profile): void { p...Votes: 0GitHub stars: 549
- Angular FormsAngular forms anti-patterns: - Using template-driven forms for non-trivial inputs; prefer Reactive Forms. - Using an untyped `FormGroup`; define `FormGroup<T>` with explicit control types. - Allowing nullable controls unintentionally; use `fb.nonNullable.group(...)` or `{ nonNullable: true }`. - Keeping validation logic inside the component; extract standalone validator functions into a separate `validators.ts`. - Subscribing to `valueChanges` without lifecycle cleanup; use `takeUntilDestroye...Votes: 0GitHub stars: 549
- Angular Http ClientAssuming a modern Angular app: 1. Configure `HttpClient` in `app.config.ts`: ```ts import { ApplicationConfig } from '@angular/core'; import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http'; import { authInterceptor } from './auth.interceptor'; export const appConfig: ApplicationConfig = { providers: [ provideHttpClient( withFetch(), withInterceptors([authInterceptor]) ), ], }; ``` 2. Use functional interceptors with `HttpInterceptorFn`: ```ts import { HttpInterc...Votes: 0GitHub stars: 549
- Angular Http ClientUse `HttpInterceptorFn` and register it with `withInterceptors`: ```ts // auth.interceptor.ts import { HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; import { AuthService } from './auth.service'; export const authInterceptor: HttpInterceptorFn = (req, next) => { const token = inject(AuthService).getToken(); const request = token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}`, }, }) : req; return next(request); }; ``` Register it in `app....Votes: 0GitHub stars: 549
- Angular Http ClientUse `httpResource<T>()` inside a service. Read signals in its request function; Angular then **auto-refetches** whenever those signals change. ```ts import { Injectable, signal } from '@angular/core'; import { httpResource, HttpClient } from '@angular/common/http'; interface User { id: string; name: string; } @Injectable({ providedIn: 'root' }) export class UserService { private readonly userId = signal('42'); readonly userResource = httpResource<User>( () => `/api/users/${this.userId()}` ); ...Votes: 0GitHub stars: 549
- Angular Http ClientIn `user.service.ts`, encapsulate all HTTP calls in the service and use typed responses with `inject(HttpClient)`: ```ts import { inject, Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { catchError, shareReplay, throwError } from 'rxjs'; export interface User { id: string; name: string; } @Injectable({ providedIn: 'root' }) export class UserService { private readonly http = inject(HttpClient); private readonly usersUrl = '/api/users'; readonly use...Votes: 0GitHub stars: 549
- Angular Http ClientUse a functional `HttpInterceptorFn` registered globally with `provideHttpClient` and `withInterceptors`: ```ts // error.interceptor.ts import { HttpContextToken, HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; import { catchError, throwError } from 'rxjs'; import { NotificationService } from './notification.service'; export const SKIP_ERROR_HANDLING = new HttpContextToken(() => false); export const errorInterceptor: HttpInterceptorFn = (req, next) => ...Votes: 0GitHub stars: 549
- Angular Http ClientUse Angular’s `resource<T, P>` when the async operation is not an HTTP request. Provide a reactive `request` signal and an async `loader`: ```ts import { Injectable, signal, resource, inject } from '@angular/core'; import { UserStore } from './user.store'; import { NotificationService } from './notification.service'; @Injectable() export class UserService { private readonly store = inject(UserStore); private readonly notifications = inject(NotificationService); readonly userId = signal('42');...Votes: 0GitHub stars: 549
- Angular PerformanceAssuming a modern Angular app: - Use `ChangeDetectionStrategy.OnPush` on every component. Components then update primarily when Inputs change or Signals for state change. ```ts @Component({ changeDetection: ChangeDetectionStrategy.OnPush, template: ` @for (item of items(); track item.id) { <app-row [item]="item" /> } ` }) export class ListComponent { items = signal<Item[]>([]); } ``` Use a stable unique identifier with `@for (item of items; track item.id)`. The `track` expression replaces `tr...Votes: 0GitHub stars: 549
- Angular PerformanceUse Angular’s `@defer` block around the heavy component. Angular automatically places deferred dependencies in a separate lazy-loaded chunk. ```html <!-- dashboard.component.html --> @defer (on viewport) { <app-heavy-chart /> } @placeholder { <app-spinner /> } ``` Common trigger options: ```html @defer (on interaction) { <app-heavy-editor /> } @placeholder { <p>Click to load the editor.</p> } ``` ```html @defer (on idle) { <app-heavy-report /> } @placeholder { <app-spinner /> } ``` ```html @d...Votes: 0GitHub stars: 549
- Angular PerformanceUse `NgOptimizedImage` and mark the above-the-fold hero image—the likely LCP element—with the `priority` attribute. ```ts import { ChangeDetectionStrategy, Component } from '@angular/core'; import { NgOptimizedImage } from '@angular/common'; @Component({ selector: 'app-home', standalone: true, imports: [NgOptimizedImage], template: ` <img ngSrc="https://cdn.example.com/hero.jpg" width="1600" height="900" priority alt="Product dashboard" /> `, changeDetection: ChangeDetectionStrategy.OnPush, }...Votes: 0GitHub stars: 549
- Angular PerformanceYes—avoid function calls in Angular template bindings such as: ```html {{ calculate() }} ``` They re-evaluate on every change detection cycle. Use Signals for state with a `computed()` signal instead: ```ts total = computed(() => this.price() * this.quantity()); ``` ```html {{ total() }} ``` A `computed()` signal caches until dependencies change. Pure pipes are another suitable option. Event handlers such as `(click)="save()"` are normal and aren’t the same performance concern.Votes: 0GitHub stars: 549
- Angular PerformancePrepare Angular for zoneless rendering by making components signal-driven and opting into zoneless change detection: ```ts // main.ts import { bootstrapApplication } from '@angular/platform-browser'; import { provideExperimentalZonelessChangeDetection } from '@angular/core'; import { AppComponent } from './app/app.component'; bootstrapApplication(AppComponent, { providers: [ provideExperimentalZonelessChangeDetection(), ], }); ``` Use `ChangeDetectionStrategy.OnPush` everywhere: ```ts @Compon...Votes: 0GitHub stars: 549
- Angular PerformanceIn modern Angular, `@for` uses a `track` expression instead of a `trackBy` function: ```ts items = [ { id: 1, name: 'Apple' }, { id: 2, name: 'Orange' }, ]; ``` ```html @for (item of items; track item.id) { <p>{{ item.name }}</p> } ``` Use a stable unique identifier such as `item.id`. The `track` expression replaces `trackBy` and helps Angular reuse existing DOM nodes instead of destroying and recreating them. For older `*ngFor` syntax: ```html <div *ngFor="let item of items; trackBy: trackBy...Votes: 0GitHub stars: 549
- Angular RoutingUse Angular Router with lazy-loaded routes: ```ts // app.routes.ts import { Routes } from '@angular/router'; export const routes: Routes = [ { path: 'dashboard', loadComponent: () => import('./dashboard/dashboard.component') .then(m => m.DashboardComponent), title: 'Dashboard', }, { path: 'admin', loadChildren: () => import('./admin/admin.routes') .then(m => m.ADMIN_ROUTES), }, ]; ``` Configure the router with component input binding: ```ts // app.config.ts import { ApplicationConfig } from '...Votes: 0GitHub stars: 549
- Angular RoutingUse a functional `CanActivateFn` guard. Class-based guards are deprecated. ```ts // auth.guard.ts import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { AuthService } from './auth.service'; export const authGuard: CanActivateFn = (_route, state) => { const auth = inject(AuthService); const router = inject(Router); return auth.isLoggedIn() ? true : router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url }, }); }; ``` Apply it to...Votes: 0GitHub stars: 549
- Angular RoutingEnable component input binding when configuring the router: ```ts import { provideRouter, withComponentInputBinding } from '@angular/router'; bootstrapApplication(AppComponent, { providers: [ provideRouter(routes, withComponentInputBinding()), ], }); ``` Define a matching input in the component: ```ts // routes.ts export const routes: Routes = [ { path: 'users/:id', loadComponent: () => import('./user.component') .then(m => m.UserComponent), }, ]; // user.component.ts import { Component, inpu...Votes: 0GitHub stars: 549
- Angular RoutingAssuming a standalone Angular app, keep `app.routes.ts` declarative and lazy-load every feature: ```ts // app.routes.ts import { Routes } from '@angular/router'; import { authGuard } from './core/guards/auth.guard'; import { dashboardResolver } from './core/resolvers/dashboard.resolver'; export const routes: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'dashboard', }, { path: 'dashboard', canActivate: [authGuard], // functional CanActivateFn resolve: { data: dashboardResolver, // Res...Votes: 0GitHub stars: 549
- Angular RoutingUse a functional `ResolveFn<T>` and attach it to the route’s `resolve` property. Angular completes the resolver before activating the component. ```ts // dashboard.resolver.ts import { inject } from '@angular/core'; import { ResolveFn } from '@angular/router'; import { Dashboard } from './dashboard.model'; import { DashboardService } from './dashboard.service'; export const dashboardResolver: ResolveFn<Dashboard> = () => inject(DashboardService).getDashboard(); ``` ```ts // app.routes.ts impo...Votes: 0GitHub stars: 549
- Angular RoutingUse the route’s `title` property. Angular’s default `TitleStrategy` updates `document.title` automatically. ```ts import { Routes } from '@angular/router'; export const routes: Routes = [ { path: 'dashboard', title: 'Dashboard', loadComponent: () => import('./dashboard/dashboard.component') .then(m => m.DashboardComponent), }, ]; ``` Configure the router: ```ts bootstrapApplication(AppComponent, { providers: [ provideRouter(routes, withComponentInputBinding()), ], }); ``` For dynamic titles, ...Votes: 0GitHub stars: 549
- Angular Rxjs InteropUse `toSignal` from `@angular/core/rxjs-interop`: ```typescript import { Component, inject } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { UserService } from './user.service'; @Component({ selector: 'app-user', template: `{{ user()?.name ?? 'Loading...' }}`, }) export class UserComponent { private readonly userService = inject(UserService); readonly user = toSignal(this.userService.user$, { initialValue: null, }); } ``` The resulting `user` is a signal,...Votes: 0GitHub stars: 549
- Angular Rxjs InteropInject `HttpClient`, create the GET Observable, and expose it as a signal with a template-safe initial value: ```typescript import { Component, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { toSignal } from '@angular/core/rxjs-interop'; import { catchError, of } from 'rxjs'; interface User { id: number; name: string; } @Component({ selector: 'app-users', template: ` @for (user of users(); track user.id) { <p>{{ user.name }}</p> } `, }) export class ...Votes: 0GitHub stars: 549
- Angular Rxjs InteropConvert the signal to an Observable with `toObservable`, apply the RxJS pipeline, and convert the result back to a signal when the result is rendered by the template: ```typescript import { Component, inject, signal } from '@angular/core'; import { toObservable, toSignal } from '@angular/core/rxjs-interop'; import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs'; import { SearchService } from './search.service'; @Component({ selector: 'app-search', template: ` <input [value]="que...Votes: 0GitHub stars: 549
- Angular Rxjs InteropFor an Observable that is displayed in a template, prefer `toSignal`; it subscribes and automatically unsubscribes with the component: ```typescript readonly users = toSignal(this.userService.users$, { initialValue: [] }); ``` For a manual subscription, scope it with `takeUntilDestroyed`: ```typescript import { DestroyRef, inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { NotificationService } from './notification.service'; export class N...Votes: 0GitHub stars: 549
- Angular Rxjs InteropImport `takeUntilDestroyed` from `@angular/core/rxjs-interop` and place it in the Observable pipeline before subscribing: ```typescript import { Component, DestroyRef, inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ClockService } from './clock.service'; @Component({ selector: 'app-clock', template: `{{ latestTime }}`, }) export class ClockComponent { private readonly destroyRef = inject(DestroyRef); latestTime = ''; constructor(private...Votes: 0GitHub stars: 549
- Angular Rxjs InteropSignals do not provide RxJS operators directly. Convert the signal to an Observable, debounce that stream, and convert the result back to a signal when the result is used by the template: ```typescript import { Component, inject, signal } from '@angular/core'; import { toObservable, toSignal } from '@angular/core/rxjs-interop'; import { catchError, debounceTime, distinctUntilChanged, filter, of, switchMap, } from 'rxjs'; @Component({ selector: 'app-product-search', template: ` <input [value]=...Votes: 0GitHub stars: 549
- Angular SecurityAngular escapes interpolated values by default, so render untrusted content as text: ```html <p>{{ userInput }}</p> ``` Do not put user-controlled data in `innerHTML`, and do not call `bypassSecurityTrustHtml`, `bypassSecurityTrustUrl`, or similar trust APIs on data received from a user or an external request. If HTML really must be displayed, bind through Angular's contextual sanitizer and review the source and allowed context carefully: ```typescript import { DomSanitizer, SecurityContext }...Votes: 0GitHub stars: 549
- Angular SecurityFirst decide whether the content needs to be HTML at all. For user-generated content, render it as text so Angular escapes it: ```html <div>{{ content }}</div> ``` If HTML is required, pass it through Angular's HTML sanitizer and bind the sanitized result. For example: ```typescript import { Component, Input, inject } from '@angular/core'; import { DomSanitizer, SecurityContext } from '@angular/platform-browser'; @Component({ selector: 'app-html-preview', standalone: true, template: `<div [in...Votes: 0GitHub stars: 549
- Angular SecuritySet CSP as an HTTP response header on the production web server, reverse proxy, or SSR host—not in Angular source code. Generate a fresh, unpredictable nonce per response and use it for any legitimately inline bootstrap script or style that must remain inline. A restrictive starting policy is: ```http Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{per-request-nonce}'; style-src 'self' 'nonce-{per-request-nonce}'; img-src 'self' data: https:; connect-src 'self' https://...Votes: 0GitHub stars: 549
- Angular SecurityUsually, no. Angular sanitizes interpolated values and security-sensitive bindings. Treat every `bypassSecurityTrust*` call as a potential XSS vector, because it disables Angular's normal safety checks for that context. For untrusted or user-generated HTML, either render it as text: ```html <div>{{ content }}</div> ``` or sanitize it explicitly before binding: ```typescript const safeHtml = sanitizer.sanitize(SecurityContext.HTML, content) ?? ''; ``` Do not turn that content into a `SafeHtml`...Votes: 0GitHub stars: 549
- Angular SecurityUse a functional `CanActivateFn` and return a `UrlTree` for unauthenticated users instead of imperatively navigating inside the guard: ```typescript import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { AuthService } from './auth.service'; export const authGuard: CanActivateFn = (_route, state) => { const auth = inject(AuthService); const router = inject(Router); return auth.isAuthenticated() ? true : router.createUrlTree(['/login'], { query...Votes: 0GitHub stars: 549
- Angular SecurityDo not store bearer tokens, refresh tokens, or session secrets in `localStorage` or `sessionStorage`: JavaScript can read them after an XSS, and they persist beyond the page in ways that increase exposure. Prefer a server-managed session or token in a cookie with `HttpOnly`, `Secure`, and an appropriate `SameSite` setting. The browser then sends the auth cookie without Angular reading the secret. For same-origin requests, normal `HttpClient` requests send the cookie. For a separate API origin...Votes: 0GitHub stars: 549
- Angular SsrEnable Angular SSR and client hydration in two parts: 1. Add the SSR integration to the project: ```bash ng add @angular/ssr ``` This adds the server entry point and the SSR build/serve configuration. In `app.config.ts`, register client hydration alongside the router and HTTP client: ```ts import { ApplicationConfig } from '@angular/core'; import { provideHttpClient } from '@angular/common/http'; import { provideClientHydration, withEventReplay, } from '@angular/platform-browser'; import { pr...Votes: 0GitHub stars: 549