How to Migrate Angular App to Angular Widget for Liferay  (manually)

For big and complex applications and take advantage from some parameter and configuration as a Liferay Application, the best way to have total control over your application is by transforming manually  a native Angular Application to a Liferay Angular Widget. You need your Angular application and a new Angular widget generated by liferay-js from scratch.

Requirements: Node, Yeoman and NPM Installed

1. First, it is necessary to install liferay-js by running this command:

              npm install -g generator-liferay-js


2. Run the generator inside your “liferay-workspace/modules” or some other project folder which you are using:

                          yo liferay-js


3. Choose the “Angular Widget” type and fill in the rest of the information needed:


4. Open the src of your Angular Application and copy all HTML files to Angular Widget’s assets/app. 

5. Now copy all CSS files to Angular Widget’s assets/app/css

6. If you have some folder with static files like images, fonts, etc., take them out from these folders and copy them to Angular Widget’s assets.

7. Copy all folders and .ts files (services, model, routing*, components) from Angular Application’s over to the Angular Widget’s src/app/ folder (exceptions are app.module.ts and app.component.ts files).

You shouldn’t override the files app.component.ts' generated by Liferay because we will leverage some of the code generated there. There are some examples of how to get context information about your Angular Widget to use to reference static files, like images. About app.modules.ts, the same principle explained above applies: you shouldn’t override or delete it because we are creating a Liferay Angular Widget, and there are some differences to an ordinary Angular App to take account. For example “don't bootstrap any component statically”. 

8. Open the Angular Widget’s app.component.ts file and pay attention to the @Component There is a setting: the “templateUrl” which has the reference to the theme used plus project plus html path. Following this sample, you will need to do the same for all components to reference its “html” files.

9. Now open Angular Widget’s app.component.ts file. 


         a. Here the most important point is the templateUrl which has the reference to  the project as explained before. 

        b. The second important thing to highlight is the LiferayParams as displayed on the sample code. Through LiferayParams you have access to configuration, portlet-namespace, context-path (useful to compose the static files URLs) and the portlet-element-id.

       c. The last thing to pay attention to is the Liferay JS Object, with a lot of utils to use in a Liferay Environment. In this sample you can see how to use the internationalization. 

So, after knowing these points you will be able to do the changes from Angular Application’s app.component.ts for Angular Widget’s app.component.ts. Do it!

10. Open Angular Widget’s app.module.ts file. There are several comments about the restriction, so knowing these copy the code from Angular Application’s app.module.ts adapting for Angular Widget’s app.module.ts.

       a. In @NgModule, all services should be added to the AppModule providers array.

11. Install the missed “dependencies” or copy and paste from Application’s package.json to Angular Widget’s package.json (Don’t delete the existing dependencies, unless you know what you are doing).

Ok. So now we have all files imported for Angular Widget, close the Angular Application project… All attention for the final adjustments to get ready the application migrated. 

12. Come back to CSS. If the components migrated are using styleUrl, delete it from all .ts files. As explained before, all “CSS” files were copied to the assets/css folder. Inside this folder, there is a style.css file, importing all “CSS” files.. 


         a. The style.css file is referenced in the package.json inside “portlet” properties, and it is the only css file loaded by your Widget. 


13. As a final step before implementing your Liferay Widget, you will need to add the @Inject decorator for service injection to all constructor classes. Remember: every time you need to inject a provider service you need to use @Inject.


14. After we will deploy it both project, the consumer and the provider, for that run inside each other project: 

                                 npm run deploy


Routing Angular Widget in Liferay

For routing an Angular Widget in Liferay we need to adjust some things. 

1. Add “{provide: APP_BASE_HREF, useValue: '/'}” to the app.module.ts to configure the root app injector with a base href value from which the router will compose navigation URLs. 

import {APP_BASE_HREF} from '@angular/common';

  providers: [{provide: APP_BASE_HREF, useValue: '/'}]
class AppModule {
ngDoBootstrap() {}


2. Now to prevent the client-side parameters being sent to backend Liferay DXP we need to set a router option to use a hash (i.e. /#/{route}). Open your app-routing.module.ts file and in your @NgModule decorator set it like below:

import { Routes, RouterModule } from '@angular/router';

  imports: [RouterModule.forRoot(routes,{useHash: true, enableTracing: false})],
  exports: [RouterModule]
export class AppRoutingModule { }


3. After that, deploy and test it.

npm run deploy


Inside your Liferay DXP when you call some route from your Angular Application you will see in the browser the ${domain}/#/{route}.


Hello Roselaine! Following your description I end up getting a Liferay portlet pre-wired with Angular 10 libraries, while my app is still in Angular 9. 

Would it work if I fix the package.json to reference Agnular 9 libs or do I need to upgrade my app to Angular 10 first to make it work inside a Liferay portlet?