如何在JSF复合组件的Javascript中使用属性值?

时间:2017-04-09 08:40:37

标签: javascript jsf primefaces jsf-2

对于我的一个JSF / primefaces项目,我想显示自给定日期以来经过的时间 - 想想“此条目最后一次编辑3小时前3小时”。

首先,我计算了支持bean中的时间间隔,并让视图轮询它。这意味着每秒一次ajax调用,也很容易破坏 - 不好。

所以我为这个任务制作了我的第一个简单的JSF复合组件。基本上它只是h的一个包装器:outputText:它将开始日期作为属性,然后在Javascript中,它每秒计算到当前日期的时间间隔,并相应地更新outputText。

以下是代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:composite="http://java.sun.com/jsf/composite">

    <composite:interface>

        <composite:attribute name="start" />

    </composite:interface>

    <composite:implementation>

        <div id="#{cc.clientId}" class="elapsedTime">
            <h:outputText id="outTxt" value="#{cc.attrs.start}" />
        </div>

        <script type="text/javascript">
            var outTxt = document.getElementById("#{cc.clientId}:outTxt");
            var a = outTxt.innerHTML.split(/[^0-9]/);
            var baseDate = new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]);

            function timeStringFromSeconds(s)
            {
                var hours = Math.floor((s / 86400) * 24);
                var minutes = Math.floor(((s / 3600) % 1) * 60);
                var seconds = Math.round(((s / 60) % 1) * 60);

                if (minutes &lt; 1) {
                    minutes = "00";
                } else if (minutes &lt; 10) {
                    minutes = "0" + minutes;
                }

                if (seconds &lt; 1) {
                    seconds = "00";
                } else if (seconds &lt; 10) {
                    seconds = "0" + minutes;
                }

                return(hours + ":" + minutes + ":" + seconds);
            }

            function update() {
                var currentDate = new Date();
                var elapsed = (currentDate - baseDate) / 1000;
                outTxt.innerHTML = timeStringFromSeconds(elapsed);
            }

            update();
            setInterval(update, 1000);
        </script>

    </composite:implementation>

</html>

这是按预期工作的。但是,由于我无法直接从JS检索start属性值,我让h:outputText首先显示日期值,然后JS将从呈现的HTML中检索它并将其替换为已用时间。

因此,虽然我立即更新了值,但在某些浏览器/设备上,原始日期值可以短暂显示。整个事情对我来说就像一个丑陋的解决方法。如果由于某种原因我想使用第二个属性,我根本无法使用它,所以这种方法显然是有限的/破坏的。

所以我的问题是:是否有更简洁的方法来做到这一点,例如直接访问属性(如果可能的话)?

或者这只是你在复合材料中无法做到的事情?

非常感谢!

3 个答案:

答案 0 :(得分:4)

通过仅在第一次遇到组件时呈现函数,可以避免JS函数冲突。如果您愿意将JS外部化,则可以包含xhtml中的所有内容。请BalusC

查看此帖
<cc:interface/>

<cc:implementation>
    <h:outputScript target="head" name="js/myJs.js"/>
    <div id="#{cc.clientId}">
        <h:outputText id="output" value="#{cc.attrs.value}" />
        <script>
            update("#{cc.clientId}:output");
            setInterval(update, 1000, "#{cc.clientId}:output");
        </script>
    </div>
</cc:implementation>

或者,您可以使用componentType的{​​{1}}属性完成此操作,然后使用<cc:interface/>注释注释Java类。在Java类中,如果还没有,您可以覆盖@FacesComponent(name=...将JS写入响应。 这是复合

encodeBegin

和Java代码

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:cc="http://java.sun.com/jsf/composite">

<cc:interface componentType="jsTestComp" />

<cc:implementation>
    <div id="#{cc.clientId}">
        <h:outputText id="output" value="#{cc.attrs.value}" />
        <script>
            update("#{cc.clientId}:output");
            setInterval(update, 1000, "#{cc.clientId}:output");
        </script>
    </div>
</cc:implementation>
</html>

答案 1 :(得分:2)

由于ForguesR已经pointed out,您可以使用timeago jQuery plugin

我拿了插件并将其包装成JSF component。只需添加此依赖项:

<dependency>
  <groupId>com.github.jepsar</groupId>
  <artifactId>timeago-jsf</artifactId>
  <version>1.0</version>
</dependency>

此命名空间:

xmlns:ta="http://jepsar.org/timeago"

现在,您可以使用java.util.Date属性传递value来使用该组件:

<ta:timeAgo value="#{bean.date}" />

jQuery是从PrimeFaces,BootsFaces或timeago组件加载的。

基于JSF UIViewRoot#getLocale()自动加载本地化脚本。

答案 2 :(得分:1)

实际上这不是JSF问题。您只需要使用JSF检索初始值并将其传递给脚本。而不是重新发明轮子看看http://timeago.yarp.com/。以下是演示页面中的一个简单示例:

<time class="timeago" datetime="2008-07-17T09:24:17Z">July 17, 2008</time>

这将输出:9 years ago

与axemoi建议一样,将值作为参数传递。类似的东西:

Last modified : <time class="loaded timeago" datetime="#{YourBean.lastEdited}">#{YourBean.lastEdited}</time>