Angular 17+ with standalone components and signals. Covers components, services, dependency injection, and reactive patterns. USE WHEN: user mentions "Angular", "standalone components", "signals", "dependency injection", "RxJS", "NgModules", asks about "Angular 17 patterns", "Angular signals" DO NOT USE FOR: AngularJS (v1.x) - legacy framework, React - use `frontend-react`, Vue - use `vue-composition`, Svelte - use `svelte`

GitHub
Install command
npx skhub add claude-dev-suite/angular
Markdown
SKILL.md

Angular Core Knowledge

Full Reference: See advanced.md for WebSocket service with signals, RxJS WebSocketSubject, Socket.IO integration, and room management patterns.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: angular for comprehensive documentation.

When NOT to Use This Skill

Skip this skill when:

  • Working with AngularJS (1.x) - legacy framework
  • Building React applications (use frontend-react)
  • Using Vue framework (use vue-composition)
  • Working with Svelte (use svelte)
  • Need only TypeScript without framework (use typescript)

Standalone Components (Angular 17+)

import { Component, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-counter',
  standalone: true,
  imports: [CommonModule],
  template: `
    <button (click)="increment()">
      Count: {{ count() }}
    </button>
    <p>Double: {{ double() }}</p>
  `
})
export class CounterComponent {
  count = signal(0);
  double = computed(() => this.count() * 2);

  increment() {
    this.count.update(n => n + 1);
  }
}

Signals (Angular 16+)

APIPurpose
signal()Create reactive value
computed()Derived signal
effect()Side effects
input()Signal-based input
output()Signal-based output

Dependency Injection

@Injectable({ providedIn: 'root' })
export class UserService {
  private http = inject(HttpClient);

  getUsers() {
    return this.http.get<User[]>('/api/users');
  }
}

Key Patterns

  • Prefer standalone components
  • Use signals over RxJS for simple state
  • inject() function over constructor injection
  • Lazy load routes for performance

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Using NgModules for new appsOutdated, verboseUse standalone components
Constructor injection onlyLess flexibleUse inject() function
Not using OnPush change detectionPoor performanceUse OnPush + signals
Subscribing without unsubscribeMemory leaksUse async pipe or takeUntilDestroyed()
Inline styles with CSPSecurity issuesUse external stylesheets
Not lazy loading routesLarge bundle sizeLazy load feature modules

Quick Troubleshooting

IssueLikely CauseSolution
Expression changed after checkModifying state during CDUse ChangeDetectorRef.detectChanges()
Service not foundWrong providedIn scopeCheck @Injectable({ providedIn: 'root' })
Route not loadingMissing lazy load syntaxUse loadChildren: () => import()
Signal not updating viewNot using signal setterUse .set() or .update()
Form not reactiveUsing template-driven formsUse ReactiveFormsModule
HTTP call not firingForgot to subscribeSubscribe to Observable

Production Readiness

Security

// HTTP Interceptor for auth
export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthService).getToken();
  if (token) {
    req = req.clone({
      setHeaders: { Authorization: `Bearer ${token}` }
    });
  }
  return next(req);
};

Error Handling

// Global error handler
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  private errorService = inject(ErrorTrackingService);

  handleError(error: Error): void {
    console.error('Unhandled error:', error);
    this.errorService.trackError(error);
  }
}

// Provide in app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    { provide: ErrorHandler, useClass: GlobalErrorHandler },
  ]
};

Performance

// Lazy loading routes
export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/routes').then(m => m.ADMIN_ROUTES),
    canActivate: [authGuard],
  },
];

// Change detection optimization
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})
export class OptimizedComponent {
  data = signal<Data | null>(null);
}

// Defer loading
@Component({
  template: `
    @defer (on viewport) {
      <heavy-component />
    } @placeholder {
      <skeleton-loader />
    }
  `
})
export class DeferredComponent {}

Testing

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { provideHttpClientTesting } from '@angular/common/http/testing';

describe('UserComponent', () => {
  let component: UserComponent;
  let fixture: ComponentFixture<UserComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [UserComponent],
      providers: [provideHttpClientTesting()]
    }).compileComponents();

    fixture = TestBed.createComponent(UserComponent);
    component = fixture.componentInstance;
  });

  it('should update signal', () => {
    component.count.set(5);
    expect(component.count()).toBe(5);
    expect(component.double()).toBe(10);
  });
});

Monitoring Metrics

MetricTarget
First Contentful Paint< 1.5s
Largest Contentful Paint< 2.5s
Bundle size (initial)< 200KB
Time to Interactive< 3s

Checklist

  • Standalone components (Angular 17+)
  • Signals for reactive state
  • OnPush change detection
  • Lazy loaded routes
  • @defer for heavy components
  • Virtual scrolling for lists
  • Global error handler
  • HTTP interceptors for auth
  • SSR with Angular Universal
  • Zone-less for max performance

Reference Documentation

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: angular for comprehensive documentation.

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

skills/frontend-frameworks/angular

Default branch

main

Latest commit

9496306

Tree SHA

fe4e2f1