packages/skills/skills/angular-di/SKILL.md
Implement dependency injection in Angular v20+ using inject(), injection tokens, and provider configuration. Use for service architecture, providing dependencies at different levels, creating injectable tokens, and managing singleton vs scoped services. Triggers on service creation, configuring providers, using injection tokens, or understanding DI hierarchy.
npx skillsauth add mediar-ai/skillhubz angular-diInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Configure and use dependency injection in Angular v20+ with inject() and providers.
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();
}
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);
}
}
// Recommended: providedIn
@Injectable({
providedIn: 'root',
})
export class Auth {}
// Alternative: in app.config.ts
export const appConfig: ApplicationConfig = {
providers: [
Auth,
],
};
@Component({
selector: 'app-editor',
providers: [EditorState], // New instance for each component
template: `...`,
})
export class Editor {
private editorState = inject(EditorState);
}
export const routes: Routes = [
{
path: 'admin',
providers: [Admin], // Shared within this route tree
children: [
{ path: '', component: AdminDashboard },
{ path: 'users', component: AdminUsers },
],
},
];
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,
});
// 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 },
},
},
],
};
@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;
}
}
// Provide implementation
{ provide: Logger, useClass: ConsoleLogger }
// Conditional implementation
{
provide: Logger,
useClass: environment.production
? ProductionLogger
: ConsoleLogger,
}
// Static values
{ provide: API_URL, useValue: 'https://api.example.com' }
// Configuration objects
{ provide: APP_CONFIG, useValue: { theme: 'dark', language: 'en' } }
// 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()),
}
// Alias to existing provider
{ provide: AbstractLogger, useExisting: ConsoleLogger }
// Multiple tokens pointing to same instance
providers: [
ConsoleLogger,
{ provide: Logger, useExisting: ConsoleLogger },
{ provide: ErrorLogger, useExisting: ConsoleLogger },
]
@Component({...})
export class My {
// Returns null if not provided
private analytics = inject(Analytics, { optional: true });
trackEvent(name: string) {
this.analytics?.track(name);
}
}
@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 });
}
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);
}
}
// Interceptors use multi providers internally
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([
authInterceptor,
loggingInterceptor,
errorInterceptor,
])
),
],
};
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();
}),
],
};
providers: [
provideAppInitializer(() => {
const config = inject(Config);
return config.load();
}),
provideAppInitializer(() => {
const auth = inject(Auth);
return auth.checkSession();
}),
]
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);
}
}
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.
tools
# X Twitter Scraper Use Xquik for X/Twitter tweet search, user lookup, profile tweets, follower export, media download, monitors, webhooks, posting workflows, and MCP-backed API exploration. ## Prerequisites - A Xquik API key in `XQUIK_API_KEY`. - Internet access to `https://xquik.com/api/v1`, `https://xquik.com/mcp`, and `https://docs.xquik.com`. - A clear user request that identifies the target tweets, users, accounts, keywords, media, monitor, webhook, or write action. ## Source Truth -
tools
Use when the user says "mk0r", "appmaker CLI", "open a VM", "run something in the sandbox", "talk to the VM agent", "spin up an E2B sandbox", or "chat with appmaker from CLI." Wraps the `mk0r` CLI to list projects, exec commands inside their E2B sandboxes, stream chat with the VM agent (same `/api/chat` the web UI uses), toggle SOAX residential IP, manage schedules, and copy files. Supports a sticky default project via `mk0r projects use`.
testing
Use when the user mentions "influencer candidates", "social media operator", "check proposals on Upwork/Fiverr", "review influencer applications", "qualify candidates", or "reach out to operators". Manages the IG/TikTok account operator hiring pipeline — review applicants, check replies, qualify, and do proactive outreach.
tools
End-to-end newsletter pipeline: investigate recent features, draft, send via API endpoint, and track delivery/open/click metrics.