Blogs

<portlet:namespace/>
to achieve this. So I want to test if AngularJS can achieve this.
<html ng-app="myapp"> .. </html>
ng-app
does not have to be bound to
html
tag, but it can be bound to any tag. Next question can you have multiple tags with
ng-app
attributes same time at page as we can have multiple portlets and also multiple portlet instances. Quick proof of concept proofs other vice, so there can be only one ng-app attribute per page. So AngularJS seems to be failing the portlet world, but I decided to dig deeper and after further study I did find out that ng-app can be replaced by API call:
angular.bootstrap(<dom element>,<list of modules>);
Finally, I could confirm that with this API call it is possible have multiple AngularJS modules at one page and be bound to multiple dom elements.
This did lead me to integrate this Liferay.Portlet.ready(..)
event and I did result following framework (angular-portlet.js
):
(function(Liferay, angular) { if (angular.portlet) return; angular.portlet = {}; var angularPortlets = {}; angular.portlet.add = function(pluginName, portletName, angularFunction) { var portletId = "_WAR_" + pluginName.replace(/[_]|[-]/g, ""); portletId = portletName.replace(/[_]|[-]/g, "") + portletId; angularPortlets[portletId] = angularFunction; }; Liferay.Portlet.ready(function(portletInstanceId, node) { var portletId = portletInstanceId.replace(/[_]INSTANCE[_].+/g, ""); if (angularPortlets[portletId]) { angular.bootstrap(node.getDOMNode(), angularPortlets[portletId]( portletInstanceId, node.getDOMNode())); } }); })(Liferay, angular);
The framework is using plugin name
+ portlet name
to register AngularJS modules to specific portlet. During the Liferay.portlet.ready
event the module is bound to the portlet's dom element.
Following example demonstrate how this is done:
(function(Liferay, angular) { angular.portlet.add("poc-angular-portlet", "poc-angular-portlet", function() { var myModule = angular.module("myModule", []); myModule.controller("MyController", function($scope) { $scope.mythings = [ { name : "Thing 1" }, { name : "Thing 2", } ]; $scope.add = function() { $scope.mythings.push({name: $scope.newThing.name}); }; $scope.remove = function(index) { $scope.mythings.splice(index, 1); }; }); return [ myModule.name ]; }); })(Liferay, angular);
angular.portlet.add(..)
with
plugin name
and
portlet-name
.
<div ng-controller="MyController"> <h1>My Things</h1> <input ng-model="newThing.name"/> <button ng-click="add();">Add</button> <div ng-repeat="mything in mythings"> <span>{{mything.name}}</span> <button ng-click="remove($index);">Remove</button> </div> </div>
<portlet:namespace/>
tags in HTML, since AngularJS only is scanning markup inside bootstrap element.

- The example app (with some extras) can be downloaded from here: poc-angular-portlet-6.2.0.0-SNAPSHOT.war
- The code can be found from github : https://github.com/sammso/poc-angular-portlet (fixed)
- AngularJS documentation : http://angularjs.org/
- stackoverflow : http://stackoverflow.com/questions/18571301/angularjs-multiple-ng-app-within-a-page
portal-ext.properties
minifier.enabled=false