Migrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.
Add this skill
npx mdskills install sickn33/angular-migrationComprehensive AngularJS-to-Angular migration guide with concrete code examples and hybrid patterns
1---2name: angular-migration3description: Migrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.4---56# Angular Migration78Master AngularJS to Angular migration, including hybrid apps, component conversion, dependency injection changes, and routing migration.910## Use this skill when1112- Migrating AngularJS (1.x) applications to Angular (2+)13- Running hybrid AngularJS/Angular applications14- Converting directives to components15- Modernizing dependency injection16- Migrating routing systems17- Updating to latest Angular versions18- Implementing Angular best practices1920## Do not use this skill when2122- You are not migrating from AngularJS to Angular23- The app is already on a modern Angular version24- You need only a small UI fix without framework changes2526## Instructions27281. Assess the AngularJS codebase, dependencies, and migration risks.292. Choose a migration strategy (hybrid vs rewrite) and define milestones.303. Set up ngUpgrade and migrate modules, components, and routing.314. Validate with tests and plan a safe cutover.3233## Safety3435- Avoid big-bang cutovers without rollback and staging validation.36- Keep hybrid compatibility testing during incremental migration.3738## Migration Strategies3940### 1. Big Bang (Complete Rewrite)41- Rewrite entire app in Angular42- Parallel development43- Switch over at once44- **Best for:** Small apps, green field projects4546### 2. Incremental (Hybrid Approach)47- Run AngularJS and Angular side-by-side48- Migrate feature by feature49- ngUpgrade for interop50- **Best for:** Large apps, continuous delivery5152### 3. Vertical Slice53- Migrate one feature completely54- New features in Angular, maintain old in AngularJS55- Gradually replace56- **Best for:** Medium apps, distinct features5758## Hybrid App Setup5960```typescript61// main.ts - Bootstrap hybrid app62import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';63import { UpgradeModule } from '@angular/upgrade/static';64import { AppModule } from './app/app.module';6566platformBrowserDynamic()67 .bootstrapModule(AppModule)68 .then(platformRef => {69 const upgrade = platformRef.injector.get(UpgradeModule);70 // Bootstrap AngularJS71 upgrade.bootstrap(document.body, ['myAngularJSApp'], { strictDi: true });72 });73```7475```typescript76// app.module.ts77import { NgModule } from '@angular/core';78import { BrowserModule } from '@angular/platform-browser';79import { UpgradeModule } from '@angular/upgrade/static';8081@NgModule({82 imports: [83 BrowserModule,84 UpgradeModule85 ]86})87export class AppModule {88 constructor(private upgrade: UpgradeModule) {}8990 ngDoBootstrap() {91 // Bootstrapped manually in main.ts92 }93}94```9596## Component Migration9798### AngularJS Controller → Angular Component99```javascript100// Before: AngularJS controller101angular.module('myApp').controller('UserController', function($scope, UserService) {102 $scope.user = {};103104 $scope.loadUser = function(id) {105 UserService.getUser(id).then(function(user) {106 $scope.user = user;107 });108 };109110 $scope.saveUser = function() {111 UserService.saveUser($scope.user);112 };113});114```115116```typescript117// After: Angular component118import { Component, OnInit } from '@angular/core';119import { UserService } from './user.service';120121@Component({122 selector: 'app-user',123 template: `124 <div>125 <h2>{{ user.name }}</h2>126 <button (click)="saveUser()">Save</button>127 </div>128 `129})130export class UserComponent implements OnInit {131 user: any = {};132133 constructor(private userService: UserService) {}134135 ngOnInit() {136 this.loadUser(1);137 }138139 loadUser(id: number) {140 this.userService.getUser(id).subscribe(user => {141 this.user = user;142 });143 }144145 saveUser() {146 this.userService.saveUser(this.user);147 }148}149```150151### AngularJS Directive → Angular Component152```javascript153// Before: AngularJS directive154angular.module('myApp').directive('userCard', function() {155 return {156 restrict: 'E',157 scope: {158 user: '=',159 onDelete: '&'160 },161 template: `162 <div class="card">163 <h3>{{ user.name }}</h3>164 <button ng-click="onDelete()">Delete</button>165 </div>166 `167 };168});169```170171```typescript172// After: Angular component173import { Component, Input, Output, EventEmitter } from '@angular/core';174175@Component({176 selector: 'app-user-card',177 template: `178 <div class="card">179 <h3>{{ user.name }}</h3>180 <button (click)="delete.emit()">Delete</button>181 </div>182 `183})184export class UserCardComponent {185 @Input() user: any;186 @Output() delete = new EventEmitter<void>();187}188189// Usage: <app-user-card [user]="user" (delete)="handleDelete()"></app-user-card>190```191192## Service Migration193194```javascript195// Before: AngularJS service196angular.module('myApp').factory('UserService', function($http) {197 return {198 getUser: function(id) {199 return $http.get('/api/users/' + id);200 },201 saveUser: function(user) {202 return $http.post('/api/users', user);203 }204 };205});206```207208```typescript209// After: Angular service210import { Injectable } from '@angular/core';211import { HttpClient } from '@angular/common/http';212import { Observable } from 'rxjs';213214@Injectable({215 providedIn: 'root'216})217export class UserService {218 constructor(private http: HttpClient) {}219220 getUser(id: number): Observable<any> {221 return this.http.get(`/api/users/${id}`);222 }223224 saveUser(user: any): Observable<any> {225 return this.http.post('/api/users', user);226 }227}228```229230## Dependency Injection Changes231232### Downgrading Angular → AngularJS233```typescript234// Angular service235import { Injectable } from '@angular/core';236237@Injectable({ providedIn: 'root' })238export class NewService {239 getData() {240 return 'data from Angular';241 }242}243244// Make available to AngularJS245import { downgradeInjectable } from '@angular/upgrade/static';246247angular.module('myApp')248 .factory('newService', downgradeInjectable(NewService));249250// Use in AngularJS251angular.module('myApp').controller('OldController', function(newService) {252 console.log(newService.getData());253});254```255256### Upgrading AngularJS → Angular257```typescript258// AngularJS service259angular.module('myApp').factory('oldService', function() {260 return {261 getData: function() {262 return 'data from AngularJS';263 }264 };265});266267// Make available to Angular268import { InjectionToken } from '@angular/core';269270export const OLD_SERVICE = new InjectionToken<any>('oldService');271272@NgModule({273 providers: [274 {275 provide: OLD_SERVICE,276 useFactory: (i: any) => i.get('oldService'),277 deps: ['$injector']278 }279 ]280})281282// Use in Angular283@Component({...})284export class NewComponent {285 constructor(@Inject(OLD_SERVICE) private oldService: any) {286 console.log(this.oldService.getData());287 }288}289```290291## Routing Migration292293```javascript294// Before: AngularJS routing295angular.module('myApp').config(function($routeProvider) {296 $routeProvider297 .when('/users', {298 template: '<user-list></user-list>'299 })300 .when('/users/:id', {301 template: '<user-detail></user-detail>'302 });303});304```305306```typescript307// After: Angular routing308import { NgModule } from '@angular/core';309import { RouterModule, Routes } from '@angular/router';310311const routes: Routes = [312 { path: 'users', component: UserListComponent },313 { path: 'users/:id', component: UserDetailComponent }314];315316@NgModule({317 imports: [RouterModule.forRoot(routes)],318 exports: [RouterModule]319})320export class AppRoutingModule {}321```322323## Forms Migration324325```html326<!-- Before: AngularJS -->327<form name="userForm" ng-submit="saveUser()">328 <input type="text" ng-model="user.name" required>329 <input type="email" ng-model="user.email" required>330 <button ng-disabled="userForm.$invalid">Save</button>331</form>332```333334```typescript335// After: Angular (Template-driven)336@Component({337 template: `338 <form #userForm="ngForm" (ngSubmit)="saveUser()">339 <input type="text" [(ngModel)]="user.name" name="name" required>340 <input type="email" [(ngModel)]="user.email" name="email" required>341 <button [disabled]="userForm.invalid">Save</button>342 </form>343 `344})345346// Or Reactive Forms (preferred)347import { FormBuilder, FormGroup, Validators } from '@angular/forms';348349@Component({350 template: `351 <form [formGroup]="userForm" (ngSubmit)="saveUser()">352 <input formControlName="name">353 <input formControlName="email">354 <button [disabled]="userForm.invalid">Save</button>355 </form>356 `357})358export class UserFormComponent {359 userForm: FormGroup;360361 constructor(private fb: FormBuilder) {362 this.userForm = this.fb.group({363 name: ['', Validators.required],364 email: ['', [Validators.required, Validators.email]]365 });366 }367368 saveUser() {369 console.log(this.userForm.value);370 }371}372```373374## Migration Timeline375376```377Phase 1: Setup (1-2 weeks)378- Install Angular CLI379- Set up hybrid app380- Configure build tools381- Set up testing382383Phase 2: Infrastructure (2-4 weeks)384- Migrate services385- Migrate utilities386- Set up routing387- Migrate shared components388389Phase 3: Feature Migration (varies)390- Migrate feature by feature391- Test thoroughly392- Deploy incrementally393394Phase 4: Cleanup (1-2 weeks)395- Remove AngularJS code396- Remove ngUpgrade397- Optimize bundle398- Final testing399```400401## Resources402403- **references/hybrid-mode.md**: Hybrid app patterns404- **references/component-migration.md**: Component conversion guide405- **references/dependency-injection.md**: DI migration strategies406- **references/routing.md**: Routing migration407- **assets/hybrid-bootstrap.ts**: Hybrid app template408- **assets/migration-timeline.md**: Project planning409- **scripts/analyze-angular-app.sh**: App analysis script410411## Best Practices4124131. **Start with Services**: Migrate services first (easier)4142. **Incremental Approach**: Feature-by-feature migration4153. **Test Continuously**: Test at every step4164. **Use TypeScript**: Migrate to TypeScript early4175. **Follow Style Guide**: Angular style guide from day 14186. **Optimize Later**: Get it working, then optimize4197. **Document**: Keep migration notes420421## Common Pitfalls422423- Not setting up hybrid app correctly424- Migrating UI before logic425- Ignoring change detection differences426- Not handling scope properly427- Mixing patterns (AngularJS + Angular)428- Inadequate testing429
Full transparency — inspect the skill content before installing.