Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Angular is Google's TypeScript-based frontend framework for building scalable single-page applications. It provides components, dependency injection, RxJS-based reactivity, routing, forms, HTTP client, and a powerful CLI for development.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 38% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 97% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 139% | 0% |
Angular is an opinionated, full-featured frontend framework. It uses TypeScript, components with templates, dependency injection, RxJS for async data, and a CLI for scaffolding.
bash# Create new Angular project npm i -g @angular/cli ng new my-app --routing --style=scss cd my-app ng serve
# Angular project layout
src/app/
├── app.component.ts # Root component
├── app.config.ts # Application config
├── app.routes.ts # Route definitions
├── articles/
│ ├── article-list/ # List component
│ ├── article-detail/ # Detail component
│ ├── article.service.ts # Data service
│ └── article.model.ts # Interface/type
├── auth/
│ ├── auth.service.ts
│ ├── auth.guard.ts
│ └── auth.interceptor.ts
└── shared/
├── components/
└── pipes/typescript// src/app/articles/article-list/article-list.component.ts — standalone component import { Component, inject, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterLink } from '@angular/router'; import { ArticleService } from '../article.service'; import { Article } from '../article.model'; @Component({ selector: 'app-article-list', standalone: true, imports: [CommonModule, RouterLink], template: ` <h1>Articles</h1> @for (article of articles; track article.id) { <article> <h2><a [routerLink]="['/articles', article.slug]">{{ article.title }}</a></h2> <p>{{ article.excerpt }}</p> </article> } @empty { <p>No articles found.</p> } `, }) export class ArticleListComponent implements OnInit { private articleService = inject(ArticleService); articles: Article[] = []; ngOnInit() { this.articleService.getAll().subscribe((data) => (this.articles = data)); } }
typescript// src/app/articles/article-list/article-list.component.ts — signals-based component import { Component, signal, computed, inject, OnInit } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { ArticleService } from '../article.service'; @Component({ selector: 'app-article-list', standalone: true, template: ` <input (input)="search.set($any($event.target).value)" placeholder="Search..." /> <div>{{ filteredCount() }} articles found</div> @for (article of filtered(); track article.id) { <article><h2>{{ article.title }}</h2></article> } `, }) export class ArticleListComponent { private svc = inject(ArticleService); articles = toSignal(this.svc.getAll(), { initialValue: [] }); search = signal(''); filtered = computed(() => this.articles().filter((a) => a.title.toLowerCase().includes(this.search().toLowerCase())) ); filteredCount = computed(() => this.filtered().length); }
typescript// src/app/articles/article.service.ts — injectable data service import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Article } from './article.model'; @Injectable({ providedIn: 'root' }) export class ArticleService { private http = inject(HttpClient); private baseUrl = '/api/articles'; getAll(): Observable<Article[]> { return this.http.get<Article[]>(this.baseUrl); } getBySlug(slug: string): Observable<Article> { return this.http.get<Article>(`${this.baseUrl}/${slug}`); } create(article: Partial<Article>): Observable<Article> { return this.http.post<Article>(this.baseUrl, article); } }
typescript// src/app/app.routes.ts — application routes import { Routes } from '@angular/router'; import { authGuard } from './auth/auth.guard'; export const routes: Routes = [ { path: '', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) }, { path: 'articles', loadComponent: () => import('./articles/article-list/article-list.component').then(m => m.ArticleListComponent) }, { path: 'articles/:slug', loadComponent: () => import('./articles/article-detail/article-detail.component').then(m => m.ArticleDetailComponent) }, { path: 'admin', loadComponent: () => import('./admin/admin.component').then(m => m.AdminComponent), canActivate: [authGuard] }, { path: '**', redirectTo: '' }, ];
typescript// src/app/auth/auth.guard.ts — functional route guard import { inject } from '@angular/core'; import { Router, CanActivateFn } from '@angular/router'; import { AuthService } from './auth.service'; export const authGuard: CanActivateFn = () => { const auth = inject(AuthService); const router = inject(Router); return auth.isLoggedIn() ? true : router.createUrlTree(['/login']); };
typescript// src/app/auth/auth.interceptor.ts — HTTP interceptor import { HttpInterceptorFn } from '@angular/common/http'; import { inject } from '@angular/core'; import { AuthService } from './auth.service'; export const authInterceptor: HttpInterceptorFn = (req, next) => { const token = inject(AuthService).getToken(); if (token) { req = req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next(req); };
typescript// src/app/articles/article-form/article-form.component.ts — reactive form import { Component, inject } from '@angular/core'; import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; import { ArticleService } from '../article.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-article-form', standalone: true, imports: [ReactiveFormsModule], template: ` <form [formGroup]="form" (ngSubmit)="submit()"> <input formControlName="title" placeholder="Title" /> <textarea formControlName="body" placeholder="Body"></textarea> <button type="submit" [disabled]="form.invalid">Create</button> </form> `, }) export class ArticleFormComponent { private fb = inject(FormBuilder); private svc = inject(ArticleService); private router = inject(Router); form = this.fb.nonNullable.group({ title: ['', [Validators.required, Validators.maxLength(200)]], body: ['', Validators.required], }); submit() { if (this.form.valid) { this.svc.create(this.form.getRawValue()).subscribe(() => this.router.navigate(['/articles'])); } } }
typescript// src/app/app.config.ts — application configuration import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { routes } from './app.routes'; import { authInterceptor } from './auth/auth.interceptor'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideHttpClient(withInterceptors([authInterceptor])), ], };
inject() function instead of constructor injection for cleaner codeloadComponent for smaller initial bundles@for/@if/@switch control flow syntax (Angular 17+) instead of *ngFor/*ngIfOther measured skills in the registry, with their headline benchmark lift.