首先:在门户网站上使用 AngularJS 是个好主意。到目前为止,我们只将 AngularJS 用于 portlet——我稍后会解释为什么以及如何使用。
可能的副作用和冲突
与其他 JavaScript 库或框架一样,使用 AngularJS 并没有更多的副作用。Liferay 随 AlloyUi ( http://alloyui.com/ ) 一起提供。这个 JavaScript 库基于yahoo 编写的YUI ( http://yuilibrary.com/ )。YUI 使用与 jQuery 不同的命名空间,因此您可以将 jQuery 与 AlloyUI 一起使用。如果你能够使用 jQuery 而没有任何副作用,你可能会更多地使用 AngularJS,因为 AngularJS 提供了 jQuery 的一个子集。
如果您不仅需要 AngularJS 的 jqLite 实现,还需要完整的 jQuery,您只需确保在 AngularJS 之前包含 jQuery。这可以通过更改portal_normal.vm
主题轻松完成:
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>$the_title - $company_name</title>
<script type="text/javascript" src="$javascript_folder/jquery-2.0.3.min.js" charset="utf-8"></script>
<script type="text/javascript" src="$javascript_folder/angular-1.2.7.min.js" charset="utf-8"></script>
$theme.include($top_head_include)
</head>
如果您在主题级别包含 JavaScript 文件,您可以为每个主题使用不同的版本。如果您有多个门户实例并且您没有机会在每个实例中使用相同的版本,这将非常方便。
表现
这取决于。ng-app
必须知道,如果您将指令放在 html 元素上,Angular 将解析整个网页,如您的示例所示。如果您的页面非常大并且内容很多,则可能是性能问题。因此,最好将 ngApp 指令稍微放在页面中,并通过以下方式手动初始化 ngApp:
$().ready(function() {
angular.bootstrap("css-selector", ['yourApp']);
});
在 portlet 中使用 AngularJS
有两种方法可以实现这一点。
1)在你的例子中的大 ngApp 上。你必须知道,你不能嵌套 ngApps。因此,每个 portlet 都必须是您的应用程序的一部分。使用这种方法,您将失去 portlet 可以为您的页面提供单独部分的可能性。所有 portlet 都需要知道您的 ngApp 的名称是什么,并且必须扩展这个 ngApp。如果它们使用另一个 ngApp 名称或不使用其他门户服务器,则您可能无法使用这些 portlet,而无需在其他门户服务器中进行更改。优点是您可以$rootScope
在您的所有 portlet 中共享这些,并且这些 portlet 可以以有角度的方式相互通信(例如$emit
,$on
共享服务,...)。
2) 每个portlet 都有自己的ngApp。在这种情况下,没有依赖关系。每个 portlet 都可以通过angular.bootstrap
. 此外,每个 ngApp 仅针对网页的一小部分创建,并且仅在确实需要时创建。
在这两种方式中,您都应该避免使用路由。因为routeProvider
每页只能使用一个。
我们决定使用第二种方法,以便 portlet 保持独立而不依赖于全局 ngApp。
有用的提示——我希望
Portlet 配置
您知道您可以配置您的 portlet。所以问题出现了:“我如何将我的 portlet 首选项提供给我的 angular portlet?” 当然,您可以发出 http 请求来获取它们。但这还不够,因为您拨打了不需要的电话。您的 portlet 通常是 java 服务器页面,因此最好在服务器上包含生成时的首选项并将这些信息提供给您的 Angular 应用程序。但是怎么做?
在doView
您的 portlet 的方法中,您可以创建一个 JSON 对象并将其存储在您的一个键下RenderRequest
:
public void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
PortletPreferences prefs = renderRequest.getPreferences();
Map<String, Object> values = new HashMap<String, Object>();
values.put(key, value);
renderRequest.setAttribute("config", new ObjectMapper().writeValueAsString(values));
super.doView(renderRequest, renderResponse);
}
在您的 jsp 中,您可以访问此配置属性:
<div class="hidden" portlet-config>${config}</div>
portlet-config
是解析 JSON 并将信息存储在服务实例中的指令:
.factory('portletConfigService', function(){ return {}})
.directive('portletConfig', ['portletConfigService', function(portletConfigService) {
return {
restrict: 'A',
compile: function(elem, attrs) {
var config = angular.fromJson(elem.text());
angular.forEach(config, function(value, key){
portletConfigService[key] = value;
});
}
};
}])
现在您可以将 注入portletConfigService
到每个控制器、服务、工厂或其他任何东西中,并使用 config 参数: portletConfigService.key
.
语言属性
我们遇到的另一个问题是语言属性。通常你会在一个language.properties
文件中定义它们并在你的jsp中使用它们。例如通过 fmt:message
标签。但是您还希望能够在您的 Angular js 应用程序中访问它们。而你绝对不想要的是在你的来源中有两次。我们通过生成的服务和读取当前用户语言的属性并在 jsp 中创建角度内容的指令解决了这个问题:
<%@page contentType="text/javascript; charset=UTF-8" %>
<%@ page import="java.util.ResourceBundle" %>
<%@ page import="java.util.Locale" %>
<%@ page import="java.util.Enumeration" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
angular.module('translations', [])
.factory('translations', function(){ return {
<%
ResourceBundle labels = ResourceBundle.getBundle("language", request.getLocale());
Enumeration<String> keys = labels.getKeys();
while(keys.hasMoreElements()){
String key = keys.nextElement();
out.write("\""+key+"\":\""+StringEscapeUtils.escapeJavaScript(labels.getString(key))+"\"");
if(keys.hasMoreElements()){
out.write(",\n");
}
}
%>
}})
.filter('mpbtranslate', ['translations', function(translations) {
return function(input) {
var translation = translations[input];
return translation? translation: '???'+input+'???';
};
}]);
您现在可以将这些翻译用作服务和过滤器。例如<div>{{'title' | translate}}</div>
,将在客户端评估为“Titel”。
我希望你能得到一些关于你的顾虑的有用信息。