{"componentChunkName":"component---src-templates-post-js","path":"/angularjs-three-ways/","result":{"data":{"markdownRemark":{"html":"<p class=\"disclaimer\"><img src=\"https://accesto.com/images/icons/bulb.svg\"><span>Welcome to our <a href=\"https://accesto.com/blog/tags/a2a\">From AngularJS to Angular series</a> - for teams still running AngularJS: why waiting is a risk, which migration approach fits your app, and what are the most common ways to do that in practice.</span></p>\n<p><strong>TL;DR:</strong> Yes, but not in one move. AngularJS (1.x) and Angular (2+) are different frameworks and there is no automated AngularJS-to-Angular upgrade path. There are several ways to run old and new code side by side while you move, and we have used three of them on real projects: a hybrid with ngUpgrade (two frameworks in one app), a side-by-side rewrite behind feature flags (two apps, split by URL), and an embedded strangler (new Angular mounted inside a server-rendered legacy page). Which one fits depends on how the app is built. Before migrating the first screen, decide which router, rich-text editor and component library the finished application will use. We postponed all three, and each one added rework later.</p>\n<p>One of our AngularJS migrations started with 223 source files in the legacy app. By the time its replacement was ready, the legacy app had 519. It kept growing the whole time we were rewriting it.</p>\n<p>We have done this on three applications. Two were AngularJS single-page apps. The third was a framework-less PHP application where the frontend was HTML coming out of the backend. Not an AngularJS migration in the strict sense, but it answers a question we keep getting from teams whose app is not really a SPA either, so it stays in. Each of the three needed a different mechanism. There is no tool that migrates an application end to end. The numbers below come from our own repositories, including the parts that went badly.</p>\n<h2>Why there is no automated upgrade path</h2>\n<p>AngularJS is built around <code class=\"language-text\">$scope</code>, the digest cycle and an injector that resolves dependencies by string name. Angular has classes, TypeScript, a compiler, reactivity through signals or RxJS. Some of the names overlap. The programming models do not. Controllers, directives and templates are framework-specific and have to be adapted. TypeScript, plain JavaScript and CSS that do not reach into the framework can often be reused as they are. A script or an AI tool can translate simple syntax, an <code class=\"language-text\">ng-repeat</code> into an <code class=\"language-text\">@for</code> block or a <code class=\"language-text\">$http</code> call into <code class=\"language-text\">HttpClient</code>, but no supported tool converts a whole application and preserves its behaviour.</p>\n<p>Incremental migrations usually come in one of two broad shapes. Either both frameworks share one application, or the new application lives beside the old one. Our three projects used one version of the first and two versions of the second. The hybrid family alone has two documented variants. With <a href=\"https://angular.dev/api/upgrade/static/UpgradeModule\"><code class=\"language-text\">UpgradeModule</code></a> both frameworks bootstrap together. With <a href=\"https://angular.dev/api/upgrade/static/downgradeModule\"><code class=\"language-text\">downgradeModule()</code></a> Angular starts lazily, once the first downgraded component is used. The URL split and the embedding can each be built in more than one way too.</p>\n<h2>Why \"we'll just rewrite it\" fails</h2>\n<p>On a whiteboard it looks clean. The problem shows up late.</p>\n<p>One of our projects is a B2B SaaS for PR teams. Two AngularJS 1.5 apps, a customer-facing client with 74 controllers and an admin panel with 193. In December 2020 a fresh Angular app started next to the old one, and the file counts above come from this project. Some features were built twice, once in each stack, because customers do not stop asking while you rebuild. Nineteen months in, the old app's header still did not know about the new routes.</p>\n<p>Whatever mechanism you pick has to come with a rule about where new work goes. Ours ended up as new features in the new stack only, with critical fixes still going into the old app. The freeze took hold late. How soon you can enforce a rule like that depends on how much of your roadmap touches screens nobody has migrated yet. We now start it the day the new workspace exists.</p>\n<h2>Way 1: hybrid with ngUpgrade</h2>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1300px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 44.30769230769231%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsTAAALEwEAmpwYAAABTUlEQVQoz2VRSW7DMAz0/1/Va3MrEARtbSdeJHmT5E0Lacty5SQoimYwIgiCoyHIaP8Hv3sf3j4MKk2rIu/UbB/1V0RH/Wh+8hfr6rpu5N3k3PYq8/fWaPN+NjhrUAa0RVbLJK1yImg9hEiqIS9FQeWt4LQZFKyjxkBllzBg5Pxu+3qTGbSZZulYxprFqs663rRi5r1q+JxUKmbqm8wxVbmAG4dqgGB/iEGQfSro1/l8OuWXj5A7mZFqLIIzlUnGC4GlxNOZvr2nl1yW/UKkfYpRkn3MobuqOtFtGsTQJLQaCZO06kkzFRKzznySPqnnmE2lQCLBP8RGMsfTMPmT4oqiEKNlzdDyKSRZd4yaCTwih7S1rL87h7Xh4hCXQEC0ANpYbcHiCstql9VAWA+GpWpYDT7ocHXPU/3Ftm3aHHoTvrhzVsYYsBa8/3/rH0wuAK3R9KrHAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"The first way to migrate AngularJS to Angular\"\n        title=\"Hybrid aproach to migrating AngularJS to Angular\"\n        src=\"/blog/static/367ca3f85ceea1722973b1f7a3f06c09/3c492/hybrid_ngupgrade.png\"\n        srcset=\"/blog/static/367ca3f85ceea1722973b1f7a3f06c09/ff46a/hybrid_ngupgrade.png 325w,\n/blog/static/367ca3f85ceea1722973b1f7a3f06c09/a6d36/hybrid_ngupgrade.png 650w,\n/blog/static/367ca3f85ceea1722973b1f7a3f06c09/3c492/hybrid_ngupgrade.png 1300w,\n/blog/static/367ca3f85ceea1722973b1f7a3f06c09/d544a/hybrid_ngupgrade.png 1950w,\n/blog/static/367ca3f85ceea1722973b1f7a3f06c09/b3608/hybrid_ngupgrade.png 2160w\"\n        sizes=\"(max-width: 1300px) 100vw, 1300px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p><code class=\"language-text\">@angular/upgrade/static</code> runs both frameworks inside one application. Downgrading an Angular component lets AngularJS templates render it. Upgrading an AngularJS service makes it injectable in Angular code. You move one component at a time and the application stays one application, with one deploy and one session.</p>\n<p>We did this on a team-planning SaaS. AngularJS 1.7, bumped to 1.8 along the way. About 166k lines in the legacy JavaScript and template directories, plus roughly 48k lines of AngularJS written in TypeScript left over from an earlier modernisation attempt, 161 controllers, 370 directives and 84 UI-Router states. The two peaks came at different times. Downgraded components reached 154 in October 2023. Downgraded injectables reached 80 in May 2024, when the component count was 150. Another 38 Angular services were exposed through a global registry on <code class=\"language-text\">window</code>, to AngularJS and to consumers outside Angular's dependency injection.</p>\n<p>Most of the later boundary bugs here involved dependency injection and service readiness. One file, the mention plugin of the rich-text editor, failed with an \"Unknown provider\" error in 2021 and again in 2025, two different immediate causes four years apart. The file had the location of the framework boundary written into it. The boundary had moved. Twice.</p>\n<p>UI-Router owned the route tree for most of the hybrid's life, shared by both frameworks through <code class=\"language-text\">@uirouter/angular-hybrid</code>. The first real Angular Router routes appeared in September 2024, with AngularJS still in the application, and the last UI-Router package left twelve months later, in September 2025. Some of those boundary problems reached users as routing glitches and inconsistent UI behaviour. The bootstrap races were our own doing rather than ngUpgrade's. The global registry carried services and said nothing about whether the one you wanted existed yet.</p>\n<p>Taking AngularJS out removed the largest compatibility constraint in the project and made a concentrated upgrade possible. Nine sequential update commits between 5 and 16 January 2026 took the application from Angular 12 to Angular 21, one <code class=\"language-text\">ng update</code> each, because Angular's <a href=\"https://angular.dev/update-guide\" target=\"_blank\" rel=\"nofollow\" rel=\"noopener\">supported update path</a> goes one major at a time. The chain reached the main line in May 2026. That batch went fast. Whether the majors after it stay this easy, we will find out.</p>\n<p>The price of the hybrid is that the boundary needs an owner for as long as it lives, which is a bad trade for a small team on a big app. The mention plugin is what that price looks like four years in.</p>\n<h2>Way 2: side-by-side rewrite behind feature flags</h2>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1300px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 42.15384615384615%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABHElEQVQY04WQa0vDMBSG+/9/22TiBDumbk23tUvSJM39Xs/YUFHBw/shBJ68T06zLEut1/yeGLMUemCuParndwZpezmKqI2XJoSUmx9AqfX2UMpZSeudR9g87MiqvaxextUWd9QBPGvvY25SygTLyyicDdZ64+KFSsqNssG5cO1PRYfiUoWYUEIqcHkahbahATeCZ4CtgZrIpOmOpB8mLi2YLX8NmB16qrT/0r7qVujJpdSci/dJawe1xc6ZnzIfIjsXcV6cAHjAMzjeYWCMdghh1OEeEcYU8Jwp1LOpeyW7x/1m3W3Ww/bJkwPnev6+sJRKjIkLRScBsc7DLu4rtNzjt0BRnFCg+ywJNFsP3y3NpzNUgfAtt/Py33wAZljM+uvEBI4AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"The second way to migrate AngularJS to Angular\"\n        title=\"Side-by-side aproach to migrating AngularJS to Angular\"\n        src=\"/blog/static/8af74641136a40047b00d4bb3913f17b/3c492/side_by_side_flags.png\"\n        srcset=\"/blog/static/8af74641136a40047b00d4bb3913f17b/ff46a/side_by_side_flags.png 325w,\n/blog/static/8af74641136a40047b00d4bb3913f17b/a6d36/side_by_side_flags.png 650w,\n/blog/static/8af74641136a40047b00d4bb3913f17b/3c492/side_by_side_flags.png 1300w,\n/blog/static/8af74641136a40047b00d4bb3913f17b/d544a/side_by_side_flags.png 1950w,\n/blog/static/8af74641136a40047b00d4bb3913f17b/d50e7/side_by_side_flags.png 2280w\"\n        sizes=\"(max-width: 1300px) 100vw, 1300px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>The new Angular app starts from <code class=\"language-text\">ng new</code> and shares no runtime with the old one. Two mechanisms do the work together. Nginx splits traffic by URL prefix. Requests under the project-specific <code class=\"language-text\">/en/</code> prefix reach the new app, everything else reaches the old one. A feature flag per account then decides whether links to a given screen point at the old URL or the new one. Until an account is switched, its users never see a <code class=\"language-text\">/en/</code> link. When its screens are ready you flip the flag for that account, and rollback is flipping it back. That stays true only while the new screens have not changed the data model or the API contract beyond what the old screens can read. You keep that condition alive on purpose, screen by screen.</p>\n<p>The PR software project ran this, and the mechanism itself worked. Accounts moved onto the new screens one at a time and could be moved back. A typed backend-generated map of old and new screen URLs, per-account entitlements and per-customer switching are all still in use. The integration work around it went less well. Each app handled sessions on its own, so logging out of one left the session in the other running. Keeping two apps in step needs a shared session model, either SSO with single logout or tokens issued and revoked by one backend. We maintained two headers, and before the freeze held we implemented some features twice. Swapping the rich-text editor in the middle of the migration, TinyMCE for Froala, produced bug reports for four years on its own.</p>\n<p>Do not pick this one if features keep shipping into the old app. Work on unmigrated screens then gets duplicated, or it keeps extending the life of the old app, or both.</p>\n<h2>Way 3: embedded strangler inside a server-rendered legacy app</h2>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1300px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 45.84615384615384%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsTAAALEwEAmpwYAAABVklEQVQoz22Qy1LrMBBE+f8vY8cNxQ1JHFu2Jdl6Wm9LcRwLBQILiqmurln0GWnmKf9VW87Wzm1D+457F7ftz1R+uke3fNvyr8B1vQnhpHTrevs9+l6fcHEfL2FOSrseMoQ4hKyHHGHZQoGGCeKpRRJA0aGpOFfBzouPywOOhm+ycfgsm72o97o7JlJJjNBoCNENNschHKD9dxIvlahGD0QiKj7gpGk23VDtwdsO/N+R+j3bfpZjBThoCZIRm/UI9fOuf36Fh04hfR2+4LLQRZM8VZGewnjww2Emp6zOnmOqw6RdxwKQy5mG9/sXbM3mRi54+n7ZaeVI6xnyDHoKS+NIJwilwnNue2LqwYHRAeIB9S319WiZjo9rSzVbv4S4chnwoPFgRmops4SqsjNnhhFFi0Y1CZviEnyclH/Ac7q6kO7yybj4qfm7KUo/bn104VJUkAJ+AFQ3+3RMuLJ8AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"The third way to migrate AngularJS to Angular\"\n        title=\"Embedded aproach to migrating AngularJS to Angular\"\n        src=\"/blog/static/5d2ba7e76c6ead0da99b91dfe9bfa5f7/3c492/embedded_strangler.png\"\n        srcset=\"/blog/static/5d2ba7e76c6ead0da99b91dfe9bfa5f7/ff46a/embedded_strangler.png 325w,\n/blog/static/5d2ba7e76c6ead0da99b91dfe9bfa5f7/a6d36/embedded_strangler.png 650w,\n/blog/static/5d2ba7e76c6ead0da99b91dfe9bfa5f7/3c492/embedded_strangler.png 1300w,\n/blog/static/5d2ba7e76c6ead0da99b91dfe9bfa5f7/d544a/embedded_strangler.png 1950w,\n/blog/static/5d2ba7e76c6ead0da99b91dfe9bfa5f7/b3608/embedded_strangler.png 2160w\"\n        sizes=\"(max-width: 1300px) 100vw, 1300px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>This pattern is for a legacy frontend that is mostly server-rendered HTML, with AJAX endpoints returning further HTML fragments. PHP, .NET, Rails, or AngularJS 1.x sprinkled into server-rendered pages, which is how a lot of AngularJS was actually deployed. There is no SPA to hybridise with. Ours was the framework-less PHP variant, with no usable API to build a new frontend against either. We added endpoints screen by screen.</p>\n<p>The legacy page shell renders a container for the new Angular app next to the one the legacy loader has always written into, and a URL prefix (<code class=\"language-text\">/modern/</code>) decides which of the two is in front. Screens move one at a time with a flag in the database. The bridge script loads Angular on the first modern navigation, so a page that stays legacy does not pay for the bundle. Session, backend and deploy stay as they were.</p>\n<p>We run this in a care-management SaaS for German healthcare providers. About 100 navigable screens of framework-less PHP, 15+ years old, in daily use by care teams. Fifteen months in, 23 screens have been rebuilt on Angular, each controlled by one database row and reversible without a deploy. The old screens' code has not been modified. Four things changed in the legacy app: the page shell (the Angular container and the bridge script), the menu renderer, about thirty lines in the AJAX loader and one global flag.</p>\n<p>The hard part is the bridge between the two apps. Angular bootstraps on a URL that is usually not its own, and both sides want the address bar. In our setup only the bridge writes to browser history, and the Angular container appears only after a navigation has completed. Every trap we hit sat on that seam: legacy <code class=\"language-text\">href=\"#\"</code> menu links whose history entries the Angular router tried to interpret, relative AJAX paths resolved against <code class=\"language-text\">/modern/</code>, page reloads on Angular URLs, and two writers with different HTML-entity conventions in the same tables.</p>\n<p>The bridge has its own post, with the code, browser history, reloads, failed navigations and the two wrong turns we took first, an iframe and a global XHR monkey-patch.</p>\n<p>If the app is already a SPA, use way 1 or way 2.</p>\n<h2>Which one fits?</h2>\n<table>\n<thead>\n<tr>\n<th>Your situation</th>\n<th>Mechanism</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>One big AngularJS SPA, shared state everywhere, cannot split by URL</td>\n<td>Hybrid (ngUpgrade)</td>\n</tr>\n<tr>\n<td>AngularJS SPA that can be frozen, backend has usable APIs, customers can be switched in groups</td>\n<td>Side-by-side with feature flags</td>\n</tr>\n<tr>\n<td>Server-rendered legacy (PHP, .NET, Rails, or AngularJS inside server pages), AJAX returns HTML, dozens to hundreds of screens</td>\n<td>Embedded strangler</td>\n</tr>\n<tr>\n<td>Small app, roughly under 20 screens, few custom directives (a heuristic, not a threshold)</td>\n<td>Side-by-side, or honestly a rewrite with a freeze</td>\n</tr>\n</tbody>\n</table>\n<p>We start the audit with this inventory: screens or router states, controllers and directives, services, third-party AngularJS libraries split into \"has a replacement\" and \"needs a rebuild\", and lines of templates. Those numbers narrow the options. The rest usually decides: deployment topology, authentication, how much state the screens share, what test coverage exists and how fast the product itself is changing.</p>\n<p>The three above are the ones our own projects ran. The list of options is longer:</p>\n<ul>\n<li>preparing AngularJS first: componentisation, <code class=\"language-text\">strictDi</code>, TypeScript, characterisation tests, deleting dead features;</li>\n<li>moving whole routes or screens instead of single components;</li>\n<li>several modules under <code class=\"language-text\">downgradeModule()</code>, each with its own injector;</li>\n<li>keeping UI-Router in the finished Angular app;</li>\n<li>a full rewrite with a real freeze and one cutover;</li>\n<li>migrating less than everything: removing features, freezing rarely used screens, replacing part of the product with something off the shelf;</li>\n<li>staying on AngularJS with commercial extended support (HeroDevs, XLTS.dev), which buys time with security patches rather than migrating;</li>\n<li>moving to React or Vue instead of Angular, where the side-by-side and embedded mechanisms work the same and only ngUpgrade drops out;</li>\n<li>leaving the SPA model and rendering screens on the server again, for example with HTMX or Turbo, which suits apps that are mostly forms and tables;</li>\n<li>web components or a microfrontend boundary;</li>\n<li>an iframe, which ran for 23 days in the PHP project before it came out, and which is not wrong by definition;</li>\n<li>a shared session model, SSO with single logout or a BFF for the two-session problem.</li>\n</ul>\n<p>Our post on the ngUpgrade project goes through the ones that apply to hybrids.</p>\n<h2>Three decisions to make before the first screen</h2>\n<p>Three technical decisions matter early.</p>\n<ol>\n<li>The router. UI-Router worked as the shared router for the hybrid. We decided late to replace it with the Angular Router, and that replacement ran from September 2024 to September 2025. Decide early who owns each route and in what order routes move. If UI-Router stays as the bridge, plan around its <a href=\"https://github.com/ui-router/angular-hybrid#limitations\" target=\"_blank\" rel=\"nofollow\" rel=\"noopener\">documented constraint</a> that states migrate from the leaves of the tree towards the root. If the Angular Router is the destination, plan when the handover happens.</li>\n<li>The rich-text editor. In a business app it is one of the components users touch most, and they notice a change in it immediately. Swapping one in the middle of the migration cost us four years of bug reports. We now settle the target editor before screen one.</li>\n<li>The UI kit. angular-material 1.x, ui-bootstrap, ng-table: each one either has a modern counterpart or needs a rebuild. Pick the target (PrimeNG, Angular Material, your own) before screen one, so that screen one is not rebuilt when the later screens arrive.</li>\n</ol>\n<p>State management is a smaller call, and it is worth making while you are in there anyway. Services with signals may be enough, larger workflows may justify a store like NgRx, and the two are not mutually exclusive.</p>\n<p>Then there is the part that is not technical. Somebody needs the migration as a primary responsibility, and the work needs an end date. Both migrations that took years ran next to the product roadmap with no deadline and, as the team remembers it, two or three people on them. That setup was the main source of delay, although our boundary and router choices added work of their own.</p>\n<h2>What AI changes, and what it does not</h2>\n<p>The mechanical part of a migration got much cheaper. An inventory of controllers, directives, services and routes with a dependency graph is quick work now. So is translating <code class=\"language-text\">ng-repeat</code> and <code class=\"language-text\">ng-if</code> templates into Angular control flow, rewriting <code class=\"language-text\">$http</code> and Restangular services into typed <code class=\"language-text\">HttpClient</code> calls, or generating characterisation tests for existing behaviour before anyone touches it. On bounded work like that we now budget hours where we used to budget days. Every generated piece still gets reviewed, and the characterisation tests exist because a generated translation can pass a quick review and still change behaviour.</p>\n<p>Everything around that work is unchanged: choosing the mechanism, the order of screens, where the boundary between old and new runs, the router and editor decisions above, the design of the per-screen switch and its rollback, the teardown plan. A model will draft the translation. Which behaviour may be dropped, or which database change makes a rollback unsafe, we still work out ourselves.</p>\n<h2>FAQ</h2>\n<p><strong>Can AngularJS be migrated to Angular directly?</strong></p>\n<p>No. There is no automated upgrade path. Migration means moving code piece by piece with one of the three coexistence mechanisms above, and the application keeps running during the move.</p>\n<p><strong>Is ngUpgrade the recommended way to migrate AngularJS?</strong></p>\n<p>It is Angular's official interoperability library for AngularJS hybrids (<a href=\"https://angular.dev/api/upgrade/static/UpgradeModule\" target=\"_blank\" rel=\"nofollow\" rel=\"noopener\">documentation</a>), which is not the same as the right strategy for every application. It fits large SPAs that cannot be split by URL. A boundary that stays between the frameworks for years can keep producing integration work, especially when services cross it through custom mechanisms such as our global registry, and that is why the hybrid needs an owner and an end date.</p>\n<p><strong>Can we keep releasing features during an AngularJS migration?</strong></p>\n<p>Yes, and the rule that worked was to release them into the new stack only. In our projects, continuing to ship features into the old app while replacing it was the main reason the finish line kept moving.</p>\n<p><strong>How long does an AngularJS migration take?</strong></p>\n<p>In the projects we have seen, the setup around the migration mattered more than the size of the application. The two that ran next to the product roadmap with no deadline took years. We do not quote a duration before inventorying routes, dependencies, test coverage and the rate of product change. One thing we do plan from the start is an early production milestone: one complete, user-facing screen served by the new stack behind a switch, rather than only a new workspace.</p>\n<p><strong>What happens to ui-router, angular-material, ui-bootstrap and textAngular?</strong></p>\n<p>Each one is mapped in the audit to a modern replacement or a rebuild. Routers and rich-text editors are decided first, because they are the ones that drag on if left for later.</p>","timeToRead":12,"frontmatter":{"title":"Can you migrate AngularJS to Angular? Three ways to do it","tags":["angular","modernization","a2a"],"author":"amadeusz","categories":["for-developers"],"dateUpdated":null,"customTopics":[["Angular Tooltip Directive - Part 1","/how-to-create-angular-tooltip-directive","blog"],["Angular Tooltip Directive - Part 2","/angular-tooltip-directive-part-2","blog"],["How to improve your code readability?","/how-to-improve-your-code-readability-useful-clean-code-ideas-to-know","blog"],["Drag and Drop Angular Guide","/drag-and-drop-angular","blog"]],"customCTA":["Join the team where quality matters","https://accesto.com/career/","Join now"],"customContactCTA":["Join the team where quality matters","Be proud of your code and enjoy your life, great minds are always welcomed","Join now","https://accesto.com/career/"],"customContactCTAIcon":null,"heroImage":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAABsklEQVQoz2Pg5vIjiHggiNufh8sfWZyBhyeYAOIO5uYK5OYJ5uYL5eEP4eUL4+YGCQIRAx9PBB9vJD9vJISEMPh4I+BsQbF4bcd+A5deI4+JGu7zxDTyJDTzhcQS+PijGPh5Y7k4ozjZo3i4ork4ojg5IoFcbq5oboggb5yQXJ6m6zQN9xnarn3KrjMUzOtUTGskVfIERJOBmpN0tEtNjCtVVQqMDCqMDSv0dcvUVAq0NYvNzKq1DSrltUq0bcr1HcpNQmc4ll6Wtm6RsWwS16kQksoBak7T16u2sW420Ks2M6kz0K82NqzV1CiXksiVkyuUUiiW0SjXtGlQNa808J1kX3BaxaFHw65TSqtaWKaAQYg/R5A/W1gwV0QoD0gK8ucICYBIAb4sft4sQZF8caUKe4/auKq9TnkHDRyqZC065Ky7pNRrhCWLGYQFC4QECgT5ISgfyIYgoDhISrBQXLbcxqkhIH2zU/IOfZsmZeN2LYtuVe0mYZEiBhGhMjxIWLBUVLhMRrZeTLJSRrFOUrZeSKxSSLhMSKAUKMUgKlyNH4kIVQsLVooIVQkLVQHZyFIACjyA5W3ZlvwAAAAASUVORK5CYII=","aspectRatio":1.9736842105263157,"src":"/blog/static/6401366a5f41f489fc82fc51b0f19228/f3583/angularjs_migration_hero.png","srcSet":"/blog/static/6401366a5f41f489fc82fc51b0f19228/630fb/angularjs_migration_hero.png 300w,\n/blog/static/6401366a5f41f489fc82fc51b0f19228/2a4de/angularjs_migration_hero.png 600w,\n/blog/static/6401366a5f41f489fc82fc51b0f19228/f3583/angularjs_migration_hero.png 1200w,\n/blog/static/6401366a5f41f489fc82fc51b0f19228/7adbf/angularjs_migration_hero.png 1660w","sizes":"(max-width: 1200px) 100vw, 1200px"}},"publicURL":"/blog/static/6401366a5f41f489fc82fc51b0f19228/angularjs_migration_hero.png"}},"fields":{"date":"2026-11-03"}},"authorImage":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAQBAgMF/8QAFwEAAwEAAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAABpxPI79RurHjOJ3AP/8QAGxABAQEAAgMAAAAAAAAAAAAAAQIDAAQREhP/2gAIAQEAAQUCE5OjoNBzSfTLOiE62KTB8tMJrQvwf//EABoRAAEFAQAAAAAAAAAAAAAAABEAAQMQEiL/2gAIAQMBAT8BaLnRQv8A/8QAFREBAQAAAAAAAAAAAAAAAAAAESD/2gAIAQIBAT8BY//EAB4QAAIBAwUAAAAAAAAAAAAAAAABEQIhQRASMWFx/9oACAEBAAY/AkzzSiMovxklZ7Ka7ztJc3Ekkf/EABoQAQADAQEBAAAAAAAAAAAAAAEAESExYaH/2gAIAQEAAT8hwjlcIgxLZcZq/s1FdveRGW1QvYRBTVxcKiA3mTpI7djVgCif/9oADAMBAAIAAwAAABDLH4L/xAAYEQADAQEAAAAAAAAAAAAAAAAAAREQYf/aAAgBAwEBPxCtkXCivP/EABkRAAEFAAAAAAAAAAAAAAAAAAAQESExQf/aAAgBAgEBPxCzEGp//8QAIBABAAMAAQMFAAAAAAAAAAAAAQARITFBUcFhcZGh0f/aAAgBAQABPxCqCi/J8s2GWDGMvIjVuDzOJ/WVxR8/U9GlNrLL7Q9xAs0esuMIHAxhNOsJQ4fyDEGCnCvef//Z","aspectRatio":1,"src":"/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/ea649/amadeusz.jpg","srcSet":"/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/b1092/amadeusz.jpg 11w,\n/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/1d7ec/amadeusz.jpg 21w,\n/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/ea649/amadeusz.jpg 42w,\n/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/1c2ab/amadeusz.jpg 63w,\n/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/567fa/amadeusz.jpg 84w,\n/blog/static/3a9d8eb64c85cd020e98d23f31ca0336/f4ba4/amadeusz.jpg 1536w","sizes":"(max-width: 42px) 100vw, 42px"}}}},"pageContext":{"slug":"/angularjs-three-ways/","authorImagePath":"amadeusz.jpg"}},"staticQueryHashes":["1607616503","473848531"]}