Claude-skill-registry frontend-angular-patterns
Use when editing Angular TypeScript files (.ts, .tsx) in src/Frontend/ or libs/. Provides component hierarchy, state management with PlatformVmStore, API services, reactive forms, and platform utilities for EasyPlatform Angular 19 development.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/frontend-angular-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-frontend-angular-patterns && rm -rf "$T"
manifest:
skills/data/frontend-angular-patterns/SKILL.mdsource content
Frontend Angular Code Patterns
When implementing frontend Angular code in EasyPlatform, follow these patterns exactly.
Full Pattern Reference
See the complete code patterns with examples: frontend-code-patterns.md
Quick Reference
Pattern Index
| # | Pattern | Key Interface/Contract |
|---|---|---|
| 1 | Component Hierarchy | (never extend Platform* directly) |
| 2 | Component API | , , , |
| 3 | State Store | , , , |
| 4 | API Service | Extend , , typed CRUD methods |
| 5 | Forms | , , , FormArray support |
| 6 | Advanced | , , , platform utilities |
Critical Rules
- Component Hierarchy: Extend
,AppBaseComponent
, orAppBaseVmStoreComponent
- NEVER rawAppBaseFormComponentComponent - State Management: Use
for state management - NEVER manual signalsPlatformVmStore - API Services: Extend
for HTTP calls - NEVER directPlatformApiServiceHttpClient - Subscriptions: Always use
for subscriptions - NEVER manual unsubscribe.pipe(this.untilDestroyed()) - BEM Classes: All template elements MUST have BEM classes (
)block__element --modifier - API Calls: Use
for API calls - auto-handles loading/error stateeffectSimple()
Component Hierarchy
PlatformComponent → PlatformVmComponent → PlatformFormComponent → PlatformVmStoreComponent AppBaseComponent → AppBaseVmComponent → AppBaseFormComponent → AppBaseVmStoreComponent FeatureComponent extends AppBaseVmStoreComponent<State, Store>
Platform Component API
// PlatformComponent status$: WritableSignal<'Pending'|'Loading'|'Success'|'Error'>; observerLoadingErrorState<T>(key?: string): OperatorFunction<T, T>; isLoading$(key?: string): Signal<boolean | null>; untilDestroyed<T>(): MonoTypeOperatorFunction<T>; tapResponse<T>(next?, error?, complete?): OperatorFunction<T, T>; // PlatformVmStoreComponent constructor(public store: TStore) {} vm: Signal<T | undefined>; reload(): void; // PlatformFormComponent form: FormGroup<PlatformFormGroupControls<T>>; mode: 'create'|'update'|'view'; validateForm(): boolean; abstract initialFormConfig: () => PlatformFormConfig<T>;
Anti-Patterns
// ❌ Direct HttpClient → ✅ Extend PlatformApiService // ❌ Manual signals → ✅ Use PlatformVmStore // ❌ Missing untilDestroyed() → ✅ Always use .pipe(this.untilDestroyed()) // ❌ No BEM classes → ✅ Every element needs BEM class
Templates
Component with Store Template
@Component({ selector: 'app-{entity}-list', template: ` <app-loading [target]="this"> @if (vm(); as vm) { @for (item of vm.items; track item.id) { <div class="{entity}-list__item">{{item.name}}</div> } } </app-loading> `, providers: [{Entity}Store] }) export class {Entity}Component extends AppBaseVmStoreComponent<{Entity}State, {Entity}Store> { ngOnInit() { this.store.load(); } }
API Service Template
@Injectable({ providedIn: 'root' }) export class {Entity}ApiService extends PlatformApiService { protected get apiUrl() { return environment.apiUrl + '/api/{Entity}'; } getAll(query?: Query): Observable<{Entity}[]> { return this.get('', query); } save(cmd: SaveCommand): Observable<Result> { return this.post('', cmd); } }
Detailed Instructions
For task-specific guidance, also reference:
- frontend-angular.instructions.md - Angular patterns
- scss-styling.instructions.md - SCSS/BEM styling