Angular Frontend

Dev Tools

Angular frontend development — project structure, routing, modules, component lifecycle, common pitfalls, and debugging. Use when building, fixing, or reviewing Angular applications (v14+).

Install

openclaw skills install angular-frontend

Angular Frontend Development

Project Structure

Standard Angular CLI layout:

src/
  app/
    app.module.ts          # Root module — declare ALL components here or import their modules
    app-routing.module.ts  # Root routing — define ALL top-level routes here
    app.component.ts       # Root component
    feature/
      feature.component.ts
      feature.component.html
      feature.component.css
  gallery/
    gallery.module.ts      # Feature module
    gallery.component.ts

Rule: Components must live under src/app/ (or a subdirectory) to be declared in AppModule. Components outside src/app/ cannot be added to AppModule declarations.

Routing

Root vs Feature Module Routes

Root routing (AppRoutingModule) — define ALL top-level routes here:

const routes: Routes = [
  { path: '', redirectTo: '/users', pathMatch: 'full' },
  { path: 'users', component: UsersComponent },
  { path: 'comments', component: CommentsComponent },
  { path: 'gallery', component: GalleryComponent },
  { path: '**', redirectTo: '/users' }
];

Feature module routingRouterModule.forChild([...]) in a feature module ONLY works if the module is lazy-loaded via loadChildren. If the feature module is eagerly imported in AppModule, routes defined in forChild are silently ignored.

Fix: Either:

  1. Move all routes to AppRoutingModule (simpler, recommended for small apps)
  2. Use lazy loading: { path: 'gallery', loadChildren: () => import('./gallery/gallery.module').then(m => m.GalleryModule) }

Common Routing Pitfalls

  • Wildcard ** route must be LAST — order matters
  • pathMatch: 'full' required on empty-path redirects, otherwise all routes match
  • Component not in declarations — if a route points to a component not declared in any module, you get a runtime error (not a build error)

Modules

Declarations

Every component, directive, and pipe must be declared in exactly ONE module:

@NgModule({
  declarations: [
    AppComponent,
    UsersComponent,
    CommentsComponent  // Must be here if used in AppModule routes
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    MatListModule,     // Material modules used in templates
    MatToolbarModule,
    MatButtonModule
  ]
})

Import Order

When a component uses Material components in its template (e.g., <mat-list>, <mat-toolbar>), the corresponding MatListModule, MatToolbarModule etc. MUST be imported in the SAME module where the component is declared.

Components

Angular 18+ Defaults to Standalone Components

Angular 18+ generates standalone components by default. If you're using NgModule pattern (non-standalone), you MUST add standalone: false to every component:

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css'],
  standalone: false    // ← REQUIRED when using NgModule declarations
})
export class UsersComponent {}

Without standalone: false, you get NG6008: Component is standalone, and cannot be declared in an NgModule.

Creating a Component

ng generate component feature-name

This creates feature-name.component.ts, .html, .css, .spec.ts and adds it to the nearest module.

Component Outside src/app/

If a component lives outside src/app/ (e.g., src/comments/), it CANNOT be added to AppModule. Options:

  1. Move it under src/app/ (recommended)
  2. Create a separate module for it and import that module

Services

Injectable Service

@Injectable({
  providedIn: 'root'  // Singleton, available everywhere
})
export class RestService {
  constructor(private httpClient: HttpClient) {}
}

HTTP Client

Always import HttpClientModule in the root module (once):

imports: [HttpClientModule]

Mock API Endpoints

reqres.in now requires x-api-key header (returns 401 without it). Use JSONPlaceholder instead for free, no-auth mock data:

  • https://jsonplaceholder.typicode.com/users — 10 users
  • https://jsonplaceholder.typicode.com/comments — 500 comments
  • https://jsonplaceholder.typicode.com/posts — 100 posts

TypeScript Configuration

moduleResolution for Angular 19+

Angular 19 with TypeScript 5.7 requires moduleResolution: "bundler" in tsconfig.json:

{
  "compilerOptions": {
    "moduleResolution": "bundler",
    "module": "ES2022",
    "target": "ES2022"
  }
}

Using the old "moduleResolution": "node" causes TS2792: Cannot find module '@angular/core'.

Common Build Errors

ErrorCauseFix
NG6001: class is listed in declarations but is not a directive, component, or pipeComponent file has wrong path or missing @Component decoratorCheck import path, ensure @Component decorator is present
NG6008: Component is standalone, and cannot be declared in an NgModuleAngular 18+ defaults to standalone; missing standalone: falseAdd standalone: false to @Component decorator
TS2307: Cannot find module '@angular/core'Wrong moduleResolution in tsconfigSet moduleResolution: "bundler" for TS 5.7+
TS2307: Cannot find moduleWrong relative import pathFrom src/app/comments/ to src/app/rest/ use ../rest/rest.service
NG2003: No suitable injection tokenService class not properly exported or providedIn missingAdd @Injectable({ providedIn: 'root' })
error NG5002: Unexpected closing tagDuplicate closing tag in HTML templateRemove duplicate </tag>
TS2307: Cannot find module 'rxjs'rxjs not installed after node_modules wipeRun npm install rxjs@7.8.1 explicitly

Template Pitfalls

  • mat-list-item with multiple lines: Use matLine directive on each line:

    <mat-list-item *ngFor="let user of users">
      <h3 matLine>{{ user.name }}</h3>
      <p matLine>{{ user.email }}</p>
    </mat-list-item>
    

    Without matLine, only the first child is visible.

  • mat-list-item height: Default height clips multi-line content. Add CSS:

    mat-list-item { height: auto !important; }
    
  • Accessibility tree vs visual rendering: browser_snapshot compact view may only show headings (h3) even when paragraphs (p) are present. Always use full=true to see all DOM content. The content IS there even if compact snapshot doesn't show it.

Build & Serve

ng build                    # Production build
ng build --configuration development  # Development build
ng serve                    # Dev server on http://localhost:4200
ng serve --host 0.0.0.0    # Accessible from other machines

Angular Version Upgrades

Updating Angular CLI & Core

Use the official update command:

npx @angular/cli@<version> update @angular/core@<version> @angular/cli@<version> @angular/material@<version>

⚠️ Don't jump more than 2-3 major versions at once. Going from 16 → 22 in one step breaks: standalone components (default in 18+), TypeScript 6 requirement, moduleResolution changes, build system (@angular/build replaces @angular-devkit/build-angular). Safe path: 16 → 17 → 19 LTS.

After Updating package.json

  1. Delete node_modules and package-lock.json:
    • Windows: Must do this manually in PowerShell/CMD — the terminal tool gets blocked by EPERM:
      Remove-Item -Recurse -Force node_modules
      Remove-Item -Force package-lock.json
      
  2. Run npm install
  3. If rxjs is missing: npm install rxjs@7.8.1
  4. Add standalone: false to all @Component decorators (Angular 18+)
  5. Update tsconfig.json — set moduleResolution: "bundler" for TS 5.7+
  6. Run ng build --configuration development to verify

Version Compatibility

AngularNode (min)TypeScriptzone.jsStandalone default
1616~5.1~0.13No
1718~5.2-5.4~0.14No
1818~5.4-5.5~0.14Yes
19 LTS18~5.5-5.7~0.15Yes
2218~5.8-6.0~0.15Yes

Key breaking changes per version:

  • 17: New control flow syntax (@if/@for), but *ngIf/*ngFor still work
  • 18: Standalone components default; NgModule still fully supported with standalone: false
  • 19: TypeScript 5.7 requires moduleResolution: "bundler"; some Material APIs change
  • 22: New build system (@angular/build); TypeScript 6.x required; webpack builder deprecated

Reducing Dependabot Alerts

Dependabot alerts in Angular projects often come from dev dependencies (build tools like @angular-devkit/build-angular, esbuild, picomatch, tar). These are NOT shipped to production. To reduce alerts:

  1. Update Angular to latest LTS version
  2. Run npm audit to check remaining vulnerabilities
  3. Remaining alerts are typically in dev dependencies only — acceptable for school/lab projects
  4. Across-repo alerts (e.g., src/library/nodejs-server-generated/) are in different sub-projects — check package-lock.json path in the alert to identify source

For monorepo Dependabot patterns, see references/dependabot-monorepo.md.

Docker Setup

For production deployment, see references/docker-setup.md covering:

  • Multi-stage Dockerfile (Node 22 → nginx Alpine)
  • nginx.conf for SPA routing
  • docker-compose.yml
  • Common issues (Docker Desktop, peer deps, 404s)

Verification Checklist

After making changes:

  1. ng build --configuration development — must pass with 0 errors
  2. ng serve — wait for "Compiled successfully"
  3. Check each route in browser
  4. Check browser console for runtime errors
  5. Verify API calls return 200 (not 401/403)