Implementing an Angular Hybrid App Part 4

The last post of this series is about the implementation of the bootstrap module in an Angular Hybrid application, that is first of all create the Angular.io main module which take care about launching the related Angularjs main module and as second step configuring UI Router routes for a new Angular.io module which will coesists with the Angularjs app routes.

This is the final activity that will bring us to complete the Hybrid application and after that we’ll be able to implement Angularjs and Angular.io components in the same environment and eventually shared components/directives/services between them.

The bootstrap module

In the Part 2 we have implemented the main Angularjs module and we have to complete it by adding the reference to the hybrid ui router:

.....
import { upgradeModule } from '@uirouter/angular-hybrid';
export const angularjsAppModule = angular.module('angularjsApp', ['ui.router', mainModule.name, blogsModule.name, postsModule.name, uiModule.name, upgradeModule.name])
.....

Now the application will be able to route to Angularjs pages.

We have completed the Angularjs module but in an Hybrid app the main module is an Angular.io one, so we have to implement it:

import { UpgradeModule } from ‘@angular/upgrade/static’;
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’;
import { UIRouterUpgradeModule, NgHybridStateDeclaration } from ‘@uirouter/angular-hybrid’;
import { angularjsAppModule } from ‘./angularjsAppModule’;

export const pagesState: NgHybridStateDeclaration = {
name: ‘home.pages.**’,
url: ‘/pages’,
loadChildren: () => import(‘./main/pages/pagesModule’).then(m => m.PagesModule)
};

@NgModule({
imports: [
BrowserModule,
UpgradeModule,
UIRouterUpgradeModule.forRoot({ states: [pagesState] })
]
})

export class AngularAppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, [angularjsAppModule.name], { strictDi: true });
}
}

The difference from a standard module is the imports of @uirouter/angular-hybrid modules; we use the NgHybridStateDeclaration to declare a new rule where all the routes that match the pattern (home.pages.*) will be redirect to the pagesModule; the syntax:

loadChildren: () => import('./main/pages/pagesModule').then(m => m.PagesModule)

means that the module will be loaded lazy.

Then we use UIRouterUpgradeModule to register the new state with forRoot method.

The last step does what we expect, that is boostrap the angularjsAppModule; after that we can create the bootstrap.ts file:


import 'zone.js';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AngularAppModule } from './angularAppModule';
import { angularjsAppModule } from './angularjsAppModule';
import { UIRouter, UrlService } from '@uirouter/core';
import { NgZone } from '@angular/core';

angularjsAppModule.config(['$urlServiceProvider', ($urlService: UrlService) => $urlService.deferIntercept()]);

platformBrowserDynamic().bootstrapModule(AngularAppModule).then(function (platformRef) {
const urlService: UrlService = platformRef.injector.get(UIRouter).urlService;

function startUIRouter() {
urlService.listen();
urlService.sync();
}

platformRef.injector.get<NgZone>(NgZone).run(startUIRouter);
});

This is the application startup and keep in the mind that we are working with Typescript modules; before the Angularjs UI Router start resolving the states we have to wait the loading of all modules, and is for this reason that we have to stop the Angularjs UI Router service interception.

Once the bootstrapModule promise is resolved we can start the urlService listener.

The last point of discussion is the name of the file (boostrap.ts) that you can find as the entry point of the Webpack configuration seen in this post.

To complete our Hybrid application we have to implement the PagesModule.

Adding PagesModule

It’s only an Angular.io module that give sense to the Hybrid application.

Let’s declare the PagesComponent:

import { Component } from '@angular/core';
import { IResource } from '../shared/OdataResource';

@Component({
selector: 'pages-component',
templateUrl: 'pages.html'
})
export class PagesComponent {
public Pages: Array<IResource>;
}

As you can see we leverage the Webpack Angular2 template loader by using the template url with an external html page.

After that we can declare the PagesModule.ts:


import { FormsModule } from '@angular/forms';
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { UIRouterUpgradeModule } from "@uirouter/angular-hybrid";
import { PagesComponent } from "./pagesComponent";

export let CONTACTS_STATES = [
{
name: "home.pages",
url: "/pages",
component: PagesComponent
}
];

@NgModule({
imports: [
CommonModule,
FormsModule,
UIRouterUpgradeModule.forChild({ states: CONTACTS_STATES }),
],
declarations: [PagesComponent],
})
class PagesModule { }

export { PagesModule };

It’s quite simple, we still use the UIRouterUpgradeModule to register child elements of the PagesModule that they will served from the AngularModule declarated before.

Summary

We are at the end of the Angular Hybrid implementation, we have seen all the steps involved in this activity.

The critical step is the introduction of the Typescript Modules, that is a long activity and leave the application in an inconsistent state; we must go to the next steps (angular/webpack installations, bootstrap modules implementations) to complete the process and go live with the new application.

Anyway the advantages introduced are evident: we can write with Typescript, we can leverage module syntax, we can develop both Angularjs and Angular.io components, we can share components between them; we can proceed to migrate the old Angularjs components to the new framework as well.

In conclusion, if you have the necessity to upgrade a big and old Angularjs application and the business give you a chance to do that, this is one of the best options that you have.

Part 1, Part 2 and Part 3 of these series of post are availables and you can find the source code of the project here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s