The following are current outstanding issues with this process that can make it difficult when using Angular2 inside Portal.
##Pain points:
- SennaJS does not work correctly when navigating away from a page containing an Angular2 component. This is due to the way ZoneJS wraps the
XMLHttpRequest.send
method. See https://github.com/angular/zone.js/blob/master/dist/zone.js#L113. I'm not sure if there is a way around this. - Currently unable to use the liferay-amd-loader to load an angular project (at least not yet). Must use SystemJS module loader.
- This should be possible, but I've not yet figured out exactly how yet.
- Node modules must be copied into /src to allow for proper typescript compilation.
- This should also be possible by configuring the TypeScript compiler in some way to look in
node_modules
.
- This should also be possible by configuring the TypeScript compiler in some way to look in
- Multiple instances/portlets using angular will break. I think this can be resolve by importing angular outside of the portlet, and bootstrapping Angular applications as they become available. Similar to this blog post: https://web.liferay.com/es/web/sampsa.sohlman/blog/-/blogs/trying-the-angularjs-with-liferay
##Steps for creating a Portlet that uses Angular2
-
Create a Portlet skeleton using the Blade CLI. More information on this can be found here: https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/creating-modules-with-blade-cli. For this tutorial I chose to create a module from the 'portlet' template. Your command should look something like the following
blade create -d path/to/angular-portlet portlet
-
Once you have a portlet skeleton, we can start creating the extra infrastructure we will need for Angular2. Lets create the following files in our
angular-portlet/portlet
directory. * package.json * gulpfile.js -
We need to create a task in our gulpfile that will compile our typescript into javascript. There are many ways to do this, but I used the
gulp-typescript
node package. -
Now that we have a task to compile our code, we need to make sure it gets called when we deploy the module. Inside our
build.gradle
we create a task of typeExecuteGulpTask
, that depends on thenpmInstall
task, and calls our task we created in our gulp file. -
Now, lets import angular's dependencies in our init.jsp `<script src="https://npmcdn.com/[email protected]?main=browser"></script>
-
Now lets create a simple Angular2 application that integrates with a service in Liferay. Please see the attached files.
-
We can now create a way to load our application inside of your portlet. Most Angular2 applications are loaded with SystemJS, which is what we'll use here. There should be a way to use the
liferay-amd-loader
for this, but I haven't quire figured out how that will work yet.
So first, lets import SystemJS like this <script src="https://npmcdn.com/[email protected]/dist/system.src.js"></script>
. And we also have to create and import a SystemJS configuration file, like so <script src="/o/angular-portlet/js/system.config.js"></script>
.
The next step is to load our application. This can be done from many places, but for my purposes I put it in our view.jsp
like so:
```
aui:script
System.import('app').then(function(module) {
module.main(Liferay);
}).catch(function(err){ console.error(err); });
</aui:script>
What's going on in this code is, SystemJS is trying to load 'app', which we have defined in our system.config.js to load our main.js file first. the code `module.main(Liferay)` is calling our main function in main.js, and passing in the Liferay global variable.
In the end, our portlet should resemble this directory structure:
angular-portlet/ └─portlet ├── build.gradle ├── package.json ├── gulpfile.js ├── bnd.bnd ├── src/main/java/portlet/portlet/ │ │── AngularPortlet.java │ └── route/ | └── AngularPortletFriendlyURLMapper.java └── resources/META-INF/ ├── friendly-url-routes/ │ └── routes.xml └── resources/ ├── init.jsp ├── view.jsp └── js/ ├── system.config.js └── app/ ├── main.ts ├── app.component.ts ├── app.routes.ts ├── country.ts └── country-detail.component.ts
what happens when you have 2+ portliest you want to use Angular 2 for? do you have a gist for how you deal with have multiple portlets in your application that you want to handle, let's say portlet 1 and portlet 2 that are independent of each other but you want to use Angular 2 for both?