Creation of Liferay theme
Create new Liferay Theme “hello-world-theme” and deploy it
- Create blank website “my-website” and create a public page “home”.
- Apply newly created “hello-world-theme” to “home” page.
- If you observe your code, you will have following structure for your newly created “hello-world-theme”:
Adding Angular to Liferay theme
1. Now, let’s add Angular files to Liferay theme
- Create new folder “templates” in “src” folder.
- Go to “build” folder and copy “portal_normal.ftl” file and place it in src > templates folder.
Your “src” folder will look like image shown below.2. Load Node Modules for Angular dependencies
- Go to your “src” folder and create “package.json” file. Paste following code:
{ “name”: “angular-quickstart”, “version”: “1.0.0”, “scripts”: { “start”: “npm run lite”, “lite”: “lite-server” }, “license”: “MIT”, “dependencies”: { “@angular/common”: “~2.4.0”, “@angular/compiler”: “~2.4.0”, “@angular/core”: “~2.4.0”, “@angular/forms”: “~2.4.0”, “@angular/http”: “~2.4.0”, “@angular/platform-browser”: “~2.4.0”, “@angular/platform-browser-dynamic”: “~2.4.0”, “@angular/router”: “~3.4.0”, “@angular/upgrade”: “~2.4.0”, “angular-in-memory-web-api”: “~0.3.1”, “core-js”: “^2.4.1”, “rxjs”: “5.0.1”, “zone.js”: “^0.8.4” }, “devDependencies”: { “concurrently”: “^3.0.0”, “lite-server”: “^2.2.2” } }
- If you want to use latest packages, go to Angular.io, and grab latest package.json file. Go to directory D:\ws\themes\hello-world-theme\src in CMD and run command “npm install”
Now you able to see “node_modules” folder created inside “src” folder.
You have all dependent modules installed in your theme > src > node_modules folder.
3. Create “App” folder inside “src” folder and create two files app.component.js and app.module.js.
Grab code and put it in app.component.js file:
(function(app) { app.AppComponent = ng.core.Component({ selector: ‘my-app’, //Application Name template: ‘<h1>Hello World : Angular 2 App</h1>’ //Template you can use <TemplateURL> also }) .Class({ constructor: function() {} }); })(window.app || (window.app = {}));
And put below code in app.module.js file:
(function(app) { app.AppModule = ng.core.NgModule({ imports: [ ng.platformBrowser.BrowserModule ], declarations: [ app.AppComponent ], bootstrap: [ app.AppComponent ] }) .Class({ constructor: function() {} }); })(window.app || (window.app = {}));
4. Now we have some files in “App” and “node_modules” folder and the complexity is how to call files from the folders because by default Liferay provides access only to CSS, JS and Images folder.
- As a solution, we have to create freemarker variables to load files from “App” and “node_modules” folder.
- Open “portal_normal.ftl” from “templates” folder and put below code inside <head> section.
<#assign appPath = “${theme_display.getPortalURL()}${theme_display.getPathThemeRoot()}/app”/> <#assign nodeModules = “${theme_display.getPortalURL()}${theme_display.getPathThemeRoot()}/node_modules”/>
Now we have ${appPath} and ${nodeModules} path available to access files inside these folders.
5. Load libraries and app files into theme. Search for <!– inject:js–><!– endinject –> text in portal_normal.ftl.
Put the below given code between <!– inject:js–><!– endinject –> comments.
<!– inject:js–> <!—1. Liferay Custom module loader –> <script> define._amd = define.amd; define.amd = false; </script> <!– 2. Load common libraries –> <script src=”${nodeModules}/core-js/client/shim.min.js”></script> <script src=”${nodeModules}/zone.js/dist/zone.js”></script> <script src=”${nodeModules}/rxjs/bundles/Rx.js”></script> <script src=”${nodeModules}/@angular/core/bundles/core.umd.js”></script> <script src=”${nodeModules}/@angular/common/bundles/common.umd.js”></script> <script src=”${nodeModules}/@angular/compiler/bundles/compiler.umd.js”></script> <script src=”${nodeModules}/@angular/platform-browser/bundles/platform-browser.umd.js”></script> <script src=”${nodeModules}/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js”></script> <!– 3. Load App ‘modules’ –> <script src=’${appPath}/app.component.js’></script> <script src=’${appPath}/app.module.js’></script> <script> (function(app) { document.addEventListener(‘DOMContentLoaded’, function() { ng.platformBrowserDynamic .platformBrowserDynamic() .bootstrapModule(app.AppModule); }); })(window.app || (window.app = {})); </script> <script> define.amd = define._amd; </script> <!– endinject –>
You will be able to see the files being loaded from ${nodeModules} and ${appPath} folder.
6. It is time to load your angular app now
- Go to <section id=”content”> in portal_normal.ftl and then insert <my-app>Loading…</my-app>
If you observe, your complete portal_normal.ftl code will look as shown below.
<html class=”${root_css_class}” dir=”<@liferay.language key=”lang.dir” />” lang=”${w3c_language_id}”> <head> <title>${the_title} – ${company_name}</title> <meta content=”initial-scale=1.0, width=device-width” name=”viewport” /> <@liferay_util[“include”] page=top_head_include /> <!– appPath Variable : to load components and module files –> <#assign appPath = “${theme_display.getPortalURL()}${theme_display.getPathThemeRoot()}/app”/> <!– nodeModules Variable : to load dependant node module files –> <#assign nodeModules = “${theme_display.getPortalURL()}${theme_display.getPathThemeRoot()}/node_modules”/> </head> <body class=”${css_class}”> <@liferay_ui[“quick-access”] contentId=”#main-content” /> <@liferay_util[“include”] page=body_top_include /> <@liferay.control_menu /> <div class=”container-fluid” id=”wrapper”> <header id=”banner” role=”banner”> <div id=”heading”> <h1 class=”site-title”> <a class=”${logo_css_class}” href=”${site_default_url}” title=”<@liferay.language_format arguments=”${site_name}” key=”go-to-x” />”> <img alt=”${logo_description}” height=”${site_logo_height}” src=”${site_logo}” width=”${site_logo_width}” /> </a> <#if show_site_name> <span class=”site-name” title=”<@liferay.language_format arguments=”${site_name}” key=”go-to-x” />”> ${site_name} </span> </#if> </h1> </div> <#if !is_signed_in> <a data-redirect=”${is_login_redirect_required?string}” href=”${sign_in_url}” id=”sign-in” rel=”nofollow”>${sign_in_text}</a> </#if> <#if has_navigation && is_setup_complete> <#include “${full_templates_path}/navigation.ftl” /> </#if> </header> <section id=”content”> <!– Load your Angular App –> <my-app>Loading…</my-app> <#if selectable> <@liferay_util[“include”] page=content_include /> <#else> ${portletDisplay.recycle()} ${portletDisplay.setTitle(the_title)} <@liferay_theme[“wrap-portlet”] page=”portlet.ftl”> <@liferay_util[“include”] page=content_include /> </@> </#if> </section> <footer id=”footer” role=”contentinfo”> <p class=”powered-by”> <@liferay.language key=”powered-by” /> <a href=”http://www.liferay.com” rel=”external”>Liferay</a> </p> </footer> </div> <@liferay_util[“include”] page=body_bottom_include /> <@liferay_util[“include”] page=bottom_include /> <!– inject:js–> <script> define._amd = define.amd; define.amd = false; </script> <!– Load common libraries –> <script src=”${nodeModules}/core-js/client/shim.min.js”></script> <script src=”${nodeModules}/zone.js/dist/zone.js”></script> <script src=”${nodeModules}/rxjs/bundles/Rx.js”></script> <!– Load Angular Dependencies –> <script src=”${nodeModules}/@angular/core/bundles/core.umd.js”></script> <script src=”${nodeModules}/@angular/common/bundles/common.umd.js”></script> <script src=”${nodeModules}/@angular/compiler/bundles/compiler.umd.js”></script> <script src=”${nodeModules}/@angular/platform-browser/bundles/platform-browser.umd.js”></script> <script src=”${nodeModules}/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js”></script> <!– Load App ‘modules’ –> <script src=’${appPath}/app.component.js’></script> <script src=’${appPath}/app.module.js’></script> <!– Calling our Angular App to page –> <script> (function(app) { document.addEventListener(‘DOMContentLoaded’, function() { ng.platformBrowserDynamic .platformBrowserDynamic() .bootstrapModule(app.AppModule); }); })(window.app || (window.app = {})); </script> <script> define.amd = define._amd; </script> <!– endinject –> </body> </html>
Once all above actions are completed, it’s time to build theme and run your App.
- “build” your theme
- “deploy” your theme
- Refresh your browser
And that’s done. Your first Angular 2.0 App in Liferay DXP is ready now.
Liferay DXP can make your Angular 2.0 application much secured. Its OOTB features and functionalities save you from lot of code work and they easily can be integrated with Angular 2.0 app. It will offer quick and rich user experience to the user. As a matter of fact, Liferay DXP has got potential to offer robust and highly scalable technology solutions. If researched and executed well, it can empower other technologies as well.
If you longing to learn more, please mail us your query.