Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
analogjs avatar

Angular Di

  • 5.3k installs
  • 594 repo stars
  • Updated March 23, 2026
  • analogjs/angular-skills

angular-di is an agent skill that implements Angular v20+ dependency injection with inject(), injection tokens, provider scopes, and initializer patterns.

About

The angular-di skill teaches dependency injection in Angular v20 and later using inject(), injection tokens, and provider configuration. Agents guide service architecture with providedIn root singletons, component-scoped instances, and route-level providers shared across child routes. Coverage spans InjectionToken creation for API_URL, APP_CONFIG, WINDOW, and LOCAL_STORAGE, plus provider types useClass, useValue, useFactory, useExisting, and multi providers for validators and HTTP interceptors. Injection options document optional, self, skipSelf, and host lookups when resolving parent or local injectors. App initializers use provideAppInitializer for async config loads and session checks before bootstrap completes. Advanced APIs include createEnvironmentInjector, runInInjectionContext, and factory tokens with providedIn root. Examples show HttpClient injection in components, signal-backed User services, conditional loggers, factory providers with deps, and VALIDATORS arrays. Triggers include service creation, provider setup, token configuration, and DI hierarchy questions. Use when configuring injectable services, scoping dependencies, or replacing constructor injection with injec.

  • Prefer inject() over constructor injection with immediate field use in components and services.
  • Root, component, and route provider scopes for singleton versus per-instance dependencies.
  • InjectionToken patterns for config values, browser globals, and factory-provided tokens.
  • Provider types useClass, useValue, useFactory, useExisting, and multi providers.
  • Optional, self, skipSelf, and host injection plus provideAppInitializer bootstrapping.

Angular Di by the numbers

  • 5,315 all-time installs (skills.sh)
  • +69 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #98 of 2,245 Frontend Development skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
At a glance

angular-di capabilities & compatibility

Capabilities
inject() field injection in components and injec · root, component, and route provider scoping patt · injectiontoken creation and value or factory pro · useclass, usevalue, usefactory, useexisting, and · optional, self, skipself, host injection and pro
Use cases
frontend · refactoring · documentation
From the docs

What angular-di says it does

Prefer `inject()` over constructor injection:
SKILL.md
Configure and use dependency injection in Angular v20+ with `inject()` and providers.
SKILL.md
Triggers on service creation, configuring providers, using injection tokens, or understanding DI hierarchy.
SKILL.md
npx skills add https://github.com/analogjs/angular-skills --skill angular-di

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs5.3k
repo stars594
Security audit3 / 3 scanners passed
Last updatedMarch 23, 2026
Repositoryanalogjs/angular-skills

How do I configure Angular dependency injection with inject(), tokens, and providers at root, component, or route scope?

Implement dependency injection in Angular v20+ using inject(), injection tokens, and provider configuration for service architecture and scoped providers.

Who is it for?

Angular developers on v20+ creating services, configuring providers, or understanding singleton versus scoped DI hierarchies.

Skip if: Skip for non-Angular frameworks or teams not using Angular standalone inject() and provider configuration.

When should I use this skill?

User creates Angular services, configures providers, uses injection tokens, or asks about DI hierarchy, optional injection, or multi providers.

What you get

Working inject() patterns, InjectionToken providers, scoped services, multi providers, and app initializer setup aligned with Angular v20+ docs.

  • facade services
  • injection token definitions
  • DI test setup

Files

SKILL.mdMarkdownGitHub ↗

Angular Dependency Injection

Configure and use dependency injection in Angular v20+ with inject() and providers.

Basic Injection

Using inject()

Prefer inject() over constructor injection:

import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { User } from './user.service';

@Component({
  selector: 'app-user-list',
  template: `...`,
})
export class UserList {
  // Inject dependencies
  private http = inject(HttpClient);
  private userService = inject(User);
  
  // Can use immediately
  users = this.userService.getUsers();
}

Injectable Services

import { Injectable, inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root', // Singleton at root level
})
export class User {
  private http = inject(HttpClient);
  
  private users = signal<User[]>([]);
  readonly users$ = this.users.asReadonly();
  
  async loadUsers() {
    const users = await firstValueFrom(
      this.http.get<User[]>('/api/users')
    );
    this.users.set(users);
  }
}

Provider Scopes

Root Level (Singleton)

// Recommended: providedIn
@Injectable({
  providedIn: 'root',
})
export class Auth {}

// Alternative: in app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    Auth,
  ],
};

Component Level (Instance per Component)

@Component({
  selector: 'app-editor',
  providers: [EditorState], // New instance for each component
  template: `...`,
})
export class Editor {
  private editorState = inject(EditorState);
}

Route Level

export const routes: Routes = [
  {
    path: 'admin',
    providers: [Admin], // Shared within this route tree
    children: [
      { path: '', component: AdminDashboard },
      { path: 'users', component: AdminUsers },
    ],
  },
];

Injection Tokens

Creating Tokens

import { InjectionToken } from '@angular/core';

// Simple value token
export const API_URL = new InjectionToken<string>('API_URL');

// Object token
export interface AppConfig {
  apiUrl: string;
  features: {
    darkMode: boolean;
    analytics: boolean;
  };
}

export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');

// Token with factory (self-providing)
export const WINDOW = new InjectionToken<Window>('Window', {
  providedIn: 'root',
  factory: () => window,
});

export const LOCAL_STORAGE = new InjectionToken<Storage>('LocalStorage', {
  providedIn: 'root',
  factory: () => localStorage,
});

Providing Token Values

// app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    { provide: API_URL, useValue: 'https://api.example.com' },
    {
      provide: APP_CONFIG,
      useValue: {
        apiUrl: 'https://api.example.com',
        features: { darkMode: true, analytics: true },
      },
    },
  ],
};

Injecting Tokens

@Injectable({ providedIn: 'root' })
export class Api {
  private apiUrl = inject(API_URL);
  private config = inject(APP_CONFIG);
  private window = inject(WINDOW);
  
  getBaseUrl(): string {
    return this.apiUrl;
  }
}

Provider Types

useClass

// Provide implementation
{ provide: Logger, useClass: ConsoleLogger }

// Conditional implementation
{
  provide: Logger,
  useClass: environment.production
    ? ProductionLogger
    : ConsoleLogger,
}

useValue

// Static values
{ provide: API_URL, useValue: 'https://api.example.com' }

// Configuration objects
{ provide: APP_CONFIG, useValue: { theme: 'dark', language: 'en' } }

useFactory

// Factory with dependencies
{
  provide: User,
  useFactory: (http: HttpClient, config: AppConfig) => {
    return new User(http, config.apiUrl);
  },
  deps: [HttpClient, APP_CONFIG],
}

// Async factory (not recommended - use provideAppInitializer)
{
  provide: CONFIG,
  useFactory: () => fetch('/config.json').then(r => r.json()),
}

useExisting

// Alias to existing provider
{ provide: AbstractLogger, useExisting: ConsoleLogger }

// Multiple tokens pointing to same instance
providers: [
  ConsoleLogger,
  { provide: Logger, useExisting: ConsoleLogger },
  { provide: ErrorLogger, useExisting: ConsoleLogger },
]

Injection Options

Optional Injection

@Component({...})
export class My {
  // Returns null if not provided
  private analytics = inject(Analytics, { optional: true });
  
  trackEvent(name: string) {
    this.analytics?.track(name);
  }
}

Self, SkipSelf, Host

@Component({
  providers: [Local],
})
export class Parent {
  // Only look in this component's injector
  private local = inject(Local, { self: true });
}

@Component({...})
export class Child {
  // Skip this component, look in parent
  private parentService = inject(ParentSvc, { skipSelf: true });

  // Only look up to host component
  private hostService = inject(Host, { host: true });
}

Multi Providers

Collect multiple values for same token:

// Token for multiple validators
export const VALIDATORS = new InjectionToken<Validator[]>('Validators');

// Provide multiple values
providers: [
  { provide: VALIDATORS, useClass: RequiredValidator, multi: true },
  { provide: VALIDATORS, useClass: EmailValidator, multi: true },
  { provide: VALIDATORS, useClass: MinLengthValidator, multi: true },
]

// Inject as array
@Injectable()
export class Validation {
  private validators = inject(VALIDATORS); // Validator[]
  
  validate(value: string): ValidationError[] {
    return this.validators
      .map(v => v.validate(value))
      .filter(Boolean);
  }
}

HTTP Interceptors (Multi Provider)

// Interceptors use multi providers internally
export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withInterceptors([
        authInterceptor,
        loggingInterceptor,
        errorInterceptor,
      ])
    ),
  ],
};

App Initializers

Run async code before app starts using provideAppInitializer:

import { provideAppInitializer, inject } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    Config,
    provideAppInitializer(() => {
      const configService = inject(Config);
      return configService.loadConfig();
    }),
  ],
};

Multiple Initializers

providers: [
  provideAppInitializer(() => {
    const config = inject(Config);
    return config.load();
  }),
  provideAppInitializer(() => {
    const auth = inject(Auth);
    return auth.checkSession();
  }),
]

Environment Injector

Create injectors programmatically:

import { createEnvironmentInjector, EnvironmentInjector, inject } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class Plugin {
  private parentInjector = inject(EnvironmentInjector);
  
  loadPlugin(providers: Provider[]): EnvironmentInjector {
    return createEnvironmentInjector(providers, this.parentInjector);
  }
}

runInInjectionContext

Run code with injection context:

import { runInInjectionContext, EnvironmentInjector, inject } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class Utility {
  private injector = inject(EnvironmentInjector);
  
  executeWithDI<T>(fn: () => T): T {
    return runInInjectionContext(this.injector, fn);
  }
}

// Usage
utilityService.executeWithDI(() => {
  const http = inject(HttpClient);
  // Use http...
});

For advanced patterns, see references/di-patterns.md.

Related skills

How it compares

Use angular-di for service-layer DI architecture; use angular-testing for Vitest and harness coverage of components using those services.

FAQ

Should I use constructor injection or inject()?

Prefer inject() over constructor injection so dependencies are available immediately as class fields.

How do I scope a service to one component instance?

Add the service to the component providers array so each component instance gets its own injector copy.

How do I provide configuration values to services?

Create an InjectionToken and register useValue or useFactory providers in app.config.ts or route providers.

Is Angular Di safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.