将AngularJS与Liferay一起使用

Mar*_*ark 7 javascript liferay liferay-theme angularjs

我会将全局AngularJS与Liferay Portal一起使用.因为,就像AngularJS的设计一样:

为何选择AngularJS?HTML非常适合声明静态文档,但是当我们尝试使用它来声明Web应用程序中的动态视图时,它就会动摇.AngularJS允许您为应用程序扩展HTML词汇表.由此产生的环境非常具有表现力,可读性和快速开发.

我会通过开发Liferay-Theme和Portlets来简单地使用html的声明性语法.

为了这个要求,我创建了新的Liferay-Theme并定制了一点portal_normal.vm:

<!DOCTYPE html>

<#include init />

<html ... ng-app="liferay">
<head>
        ...
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.min.js"></script>
    <script type="text/javascript" src="${javascript_folder}/my.js" charset="utf-8"></script>
</head>
<body class="${css_class}">
    <div ng-controller="LiferayCtrl">
Run Code Online (Sandbox Code Playgroud)

这里my.js:

angular.module('liferay', [])

.controller('LiferayCtrl', function($scope) {
    console.log("---==== Init AngularJS ====---");
    $scope.Liferay = Liferay;
});
Run Code Online (Sandbox Code Playgroud)

我可以扩展控制器,就像获取Liferay-Site名称一样.

这有什么帮助的?

因此,我可以通过声明式html语法简单地访问Liferay JavaScript值和函数,而无需像AngularJS那样直接调用JavaScript函数.

例如,现在可以通过声明性html代码获取Liferay JavaScript的值和函数,就像这里一样,用于获取Web内容显示中的当前URL:

Liferay current URL: {{Liferay.currentURL}}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,我的问题是:

  • 在Liferay中使用AngularJS global会发生哪些副作用?
  • 可能会出现性能问题吗?
  • 与其他JavaSripts冲突,例如Alloy?
  • 在Portlet中使用AngularJS?

mic*_*ael 19

首先:在门户网站上使用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之前包含jQuery,如果你需要完整的jQuery而不仅仅是AngularJS的jqLit​​e实现.这可以通过更改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>
Run Code Online (Sandbox Code Playgroud)

如果您在主题级别包含JavaScript文件,则可以为每个主题使用不同的版本.如果您有多个门户网站实例并且您没有机会在每个实例中使用相同的版本,这非常方便.

性能

这取决于.必须要知道的是,如果将ng-app指令放在html元素上,Angular将解析整个网页,如您的示例所示.如果您的页面非常大且内容很多,则可能是性能问题.因此,最好将ngApp指令放在页面中,并通过以下方式手动初始化ngApp:

$().ready(function() {
    angular.bootstrap("css-selector", ['yourApp']);
});
Run Code Online (Sandbox Code Playgroud)

在portlet中使用AngularJS

有两种方法可以实现这一目标.

1)在你的例子中的大型ngApp上.您必须知道,您无法嵌套ngApps.因此,每个portlet都必须是您应用的一部分.使用这种方法,您将失去portlet可以为页面提供单独部分的可能性.所有portlet都需要知道ngApp的名称,并且必须扩展此ngApp.如果没有其他门户网站服务器的更改,您可能不会使用这些portlet,如果它们使用另一个ngApp名称或没有.其优点是可以共享$rootScope所有的门户和门户可以与角度的方式相互通信(例如$emit,$on共享servcies,...).

2)每个portlet都有自己的ngApp.在这种情况下,没有依赖关系.每个portlet都可以实例化自己的ngApp angular.bootstrap.此外,每个ngApp仅针对网页的一小部分创建,并且仅在真正需要时才创建.

在这两种方式中,您应该避免使用路由.因为routeProvider每页只能使用一个.

我们已决定使用第二种方法,以便portlet保持个性化,而不依赖于全局ngApp.

有用的提示 - 我希望

Portlet配置

您知道可以配置portlet.所以问题出现了:"我如何向我的角度portlet提供我的portlet首选项?"当然,你可以发出一个http请求来获取它们.但这还不够,因为你做了一个不需要的电话.您的portlet通常是java服务器页面,因此在服务器上生成时包含首选项并将这些信息提供给您的角度应用程序会很不错.但是怎么样?

doViewportlet 的方法中,您可以创建一个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);
}
Run Code Online (Sandbox Code Playgroud)

在您的jsp中,您可以访问此配置属性:

<div class="hidden" portlet-config>${config}</div>
Run Code Online (Sandbox Code Playgroud)

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;
            });
        }
    };
}])
Run Code Online (Sandbox Code Playgroud)

现在你可以注入portletConfigService每个控制器,服务,工厂或其他任何东西并使用config参数: portletConfigService.key.

语言属性

我们遇到的另一个问题是语言属性.通常,您可以在language.properties文件中定义它们并在jsp中使用它们.例如通过 fmt:message标签.但您也希望能够在角度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+'???'; 
    }; 
}]);
Run Code Online (Sandbox Code Playgroud)

您现在可以将这些翻译用作服务和过滤器.例如,<div>{{'title' | translate}}</div>将在客户端评估为"Titel".

我希望你能得到一些关于你的担忧的有用信息.