# angular-hybrid **Repository Path**: mirrors_ui-router/angular-hybrid ## Basic Information - **Project Name**: angular-hybrid - **Description**: Upgrade an ng1 UI-Router app to a ng1+ng2 hybrid using ng-upgrade - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-09-26 - **Last Updated**: 2026-02-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # UI-Router angular-hybrid [![CI](https://github.com/ui-router/angular-hybrid/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/ui-router/angular-hybrid/actions/workflows/ci.yml) ### UI-Router support for Hybrid Angular/AngularJS apps This module provides [ngUpgrade](https://angular.io/docs/ts/latest/guide/upgrade.html) integration with UI-Router. It enables UI-Router to route to both AngularJS components (and/or templates) and Angular components. Your app will be hosted by AngularJS while you incrementally upgrade it to Angular. With `@uirouter/angular-hybrid` you can use either an Angular component or an AngularJS component/template as the view in a state definition. ```js import { Ng2AboutComponentClass } from "./about.ng2.component"; /// ... $stateProvider.state({ name: 'home', url: '/home', component: 'ng1HomeComponent' // AngularJS component or directive name }) .state({ name: 'about', url: '/about', component: Ng2AboutComponentClass // Angular component class reference }); .state({ name: 'other', url: '/other', template: '

Other

', // AngularJS template/controller controller: function($scope) { /* do stuff */ } }) ``` When routing to an Angular component, that component uses the standard [Angular directives (ui-view and uiSref) from `@uirouter/angular`](https://ui-router.github.io/ng2/docs/latest/modules/directives.html). When routing to an AngularJS component or template, that component uses the standard [AngularJS directives (ui-view and ui-sref) from `@uirouter/angularjs`](https://ui-router.github.io/ng1/docs/latest/modules/directives.html). See the [hybrid sample app](https://github.com/ui-router/sample-app-angular-hybrid) for a full example. ### Getting started Remove `angular-ui-router` (or `@uirouter/angularjs`) from your AngularJS app's package.json and replace it with `@uirouter/angular-hybrid`. Add the `@angular/*` dependencies. ``` dependencies: { ... "@angular/common": "^6.0.0", "@angular/compiler": "^6.0.0", "@angular/core": "^6.0.0", "@angular/platform-browser": "^6.0.0", "@angular/platform-browser-dynamic": "^6.0.0", "@angular/upgrade": "^6.0.0", ... "@uirouter/angular-hybrid": "^6.0.0", ... } ``` Remove any `ng-app` attributes from your main HTML file. We need to use manual AngularJS bootstrapping mode. #### Add AngularJS module `ui.router.upgrade` - Add 'ui.router.upgrade' to your AngularJS app module's depedencies ```js let ng1module = angular.module('myApp', ['ui.router', 'ui.router.upgrade']); ``` [_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/e4b1144d5e3e3451f0f0cc640175bb7055294fdd/app/bootstrap/ngmodule.ts#L21-L25) #### Create a root Angular NgModule - Import the `BrowserModule`, `UpgradeModule`, and a `UIRouterUpgradeModule.forRoot()` module. - Add `providers` entry for any AngularJS services you want to expose to Angular. - The module should have a `ngDoBootstrap` method which calls the `UpgradeModule`'s `bootstrap` method. ```js export function getDialogService($injector) { return $injector.get('DialogService'); } @NgModule({ imports: [ BrowserModule, // Provide angular upgrade capabilities UpgradeModule, // Provides the @uirouter/angular directives and registers // the future state for the lazy loaded contacts module UIRouterUpgradeModule.forRoot({ states: [contactsFutureState] }), ], providers: [ // Provide the SystemJsNgModuleLoader when using Angular lazy loading { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }, // Register some AngularJS services as Angular providers { provide: 'DialogService', deps: ['$injector'], useFactory: getDialogService }, { provide: 'Contacts', deps: ['$injector'], useFactory: getContactsService }, ] }) export class SampleAppModuleAngular { constructor(private upgrade: UpgradeModule) { } ngDoBootstrap() { this.upgrade.bootstrap(document.body, [sampleAppModuleAngularJS.name], { strictDi: true }); } } ``` [_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/878095bc7ed1948bb8ebf6e67d77724354393455/app/angularModule.ts#L26-L53) #### Defer intercept Tell UI-Router that it should wait until all bootstrapping is complete before doing the initial URL synchronization. ```js ngmodule.config(['$urlServiceProvider', ($urlService: UrlService) => $urlService.deferIntercept()]); ``` [_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/878095bc7ed1948bb8ebf6e67d77724354393455/app/main.ts#L38-L40) #### Bootstrap the app - Bootstrap Angular - Angular runs ngDoBootstrap() which bootstraps AngularJS - Chain off `bootstrapModule()` and tell UIRouter to synchronize the URL and listen for further URL changes - Do this in the Angular Zone to avoid "digest already in progress" errors. ```js platformBrowserDynamic() .bootstrapModule(SampleAppModuleAngular) .then((platformRef) => { // Intialize the Angular Module // get() the UIRouter instance from DI to initialize the router const urlService: UrlService = platformRef.injector.get(UIRouter).urlService; // Instruct UIRouter to listen to URL changes function startUIRouter() { urlService.listen(); urlService.sync(); } platformRef.injector.get < NgZone > NgZone.run(startUIRouter); }); ``` [_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/878095bc7ed1948bb8ebf6e67d77724354393455/app/main.ts#L42-L55) #### Route to AngularJS components/templates Your existing AngularJS routes work the same as before. ``` var foo = { name: 'foo', url: '/foo', component: 'fooComponent' }; $stateProvider.state(foo); var bar = { name: 'foo.bar', url: '/bar', templateUrl: '/bar.html', controller: 'BarController' }; $stateProvider.state(bar); ``` #### Route to Angular components Register states using either Angular or AngularJS code. Use `component:` in your state declaration. ``` var leaf = { name: 'foo.bar.leaf', url: '/leaf', component: MyNg2CommponentClass }; $stateProvider.state(leaf); ``` #### Create Angular Feature Modules (optional) ```js @NgModule({ imports: [ UIRouterUpgradeModule.forChild({ states: [featureState1, featureState2], }), ], declarations: [FeatureComponent1, FeatureComponent2], }) export class MyFeatureModule {} ``` [_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/878095bc7ed1948bb8ebf6e67d77724354393455/app/prefs/prefs.module.ts#L10-L21) Add the feature module to the root NgModule imports ```js @NgModule({ imports: [BrowserModule, UIRouterUpgradeModule.forChild({ states }), MyFeatureModule], }) class SampleAppModule {} ``` [_example_](https://github.com/ui-router/sample-app-angular-hybrid/blob/878095bc7ed1948bb8ebf6e67d77724354393455/app/angularModule.ts#L35-L36) ### Limitations: #### Nested Routing We currently support routing either Angular (2+) or AngularJS (1.x) components into an AngularJS (1.x) `ui-view`. However, we do not support routing AngularJS (1.x) components into an Angular (2+) `ui-view`. If you create an Angular (2+) `ui-view`, then any nested `ui-view` must also be Angular (2+). Because of this, apps should be migrated starting from leaf states/views and work up towards the root state/view. #### Resolve Resolve blocks on state definitions are always injected using AngularJS style string injection tokens. - UI-Router for AngularJS injects objects using string tokens, such as `'$transition$'`, `'$state'`, or `'currentUser'`. ```js resolve: { roles: ($authService, currentUser) => $authService.fetchRoles(currentUser); } ``` - UI-Router for Angular uses the [Transition.injector()](https://ui-router.github.io/ng2/docs/2.0.0/classes/transition.transition-1.html#injector) API. The resolve function receives the `Transition` object as the first argument. ```js // In Angular, the first argument to a resolve is always the Transition object // The resolver (usually) must be exported export const rolesResolver = (transition) => { const authService = transition.injector().get(AuthService); const currentUser = transition.injector().get('currentUser'); return authService.fetchRoles(currentUser); } ... resolve: { roles: rolesResolver } ``` In UI-Router for Angular/AngularJS hybrid mode, _all resolves are injected using AngularJS style_. If you need to inject Angular services by class, or need to use some other token-based injection such as an [`InjectionToken`](https://angular.io/api/core/InjectionToken), access them by injecting the `$transition$` object using string-based injection. Then, use the `Transition.injector()` API to access your services and values. ```ts import { AuthService, UserToken } from './auth.service'; // Notice that the `Transition` object is first injected // into the resolver using the '$transition$' string token export const rolesResolver = function ($transition$) { // Get the AuthService using a class token const authService: AuthService = transition.injector().get(AuthService); // Get the user object using an InjectionToken const user = transition.injector().get(UserToken); return authService.fetchRoles(user).then((resp) => resp.roles); }; export const NG2_STATE = { name: 'ng2state', url: '/ng2state', component: Ng2Component, resolve: { roles: rolesResolver, }, }; ``` #### onEnter/Exit/Retain When a state has an `onEnter`, `onExit`, or `onRetain`, they are always injected (AngularJS style), even if the state uses Angular 2+ components or is added to an `UIRouterUpgradeModule` `NgModule`. ```js export function ng2StateOnEnter(transition: Transition, svc: MyService) { console.log(transition.to().name + svc.getThing()); } ng2StateOnEnter.$inject = [Transition, 'MyService']; export const NG2_STATE = { name: 'ng2state', url: '/ng2state', onEnter: ng2StateOnEnter, }; ``` # Examples The minimal example of `@uirouter/angular-hybrid` can be found here: https://github.com/ui-router/angular-hybrid/tree/master/example A minimal example can also be found on stackblitz: https://stackblitz.com/edit/ui-router-angular-hybrid A large sample application example with lazy loaded modules can be found here: https://github.com/ui-router/sample-app-angular-hybrid The same sample application can be live-edited using Angular CLI and StackBlitz here: https://stackblitz.com/github/ui-router/sample-app-angular-hybrid/tree/angular-cli # UpgradeAdapter vs UpgradeModule Version 2.0.0 of `@uirouter/angular-hybrid` only supports `UpgradeAdapter`, which works fine but is no longer in development. Version 3.0.0+ of `@uirouter/angular-hybrid` only supports `UpgradeModule` from `@angular/upgrade/static`, which is what the Angular team actively supports for hybrid mode. Because we dropped support for `UpgradeAdapter`, current users of `@uirouter/angular-hybrid` 2.x will have to switch to `UpgradeModule` when upgrading to 3.x.