2012-04-01 126 views
1

我正在研究一个应用程序,用户将在评估一件艺术品时填写评论表单。他们可能会在表单上花费大量时间,因此我想每5分钟自动为用户保存一次。我希望我可以使用JavaScript并设置一个计时器5分钟,然后让它基本上通过Ajax执行整个表单,我可以将数据保存到数据库,以防用户断开连接等。不幸的是,我似乎无法找到任何方式来做到这一点。使用数据更新模型并不是问题,但我无法弄清楚如何让它调用方法(类似于提交时通常的动作)。我不想或不需要它重新渲染任何东西,只是让我调用一个方法来保存数据。我怎样才能做到这一点?使用jsf 2.0 ajax库调用方法

问题实施解决方案

我试图实现隐藏的命令链接的解决办法,但我得到了一些非常奇怪的行为。我不确定是什么导致了这一点。首先是一些实施背景。表单#1创建一个bean(None范围)并将其放入Flash中,然后重定向到Form#2。 Form#2是我正在写的关于实现自动保存的大型表单。 Form#2有一个ViewScoped bean。在此Bean的PostConstruct中,它从闪存中检索值,并填充属性字段。到现在为止还挺好。这完美无缺的JavaScript。我可以按命令按钮提交表单,一切都很好。但是,当我介绍JavaScript时,它执行时,我从变量中得到一个空指针异常,该变量应该由PostConstruct从Flash中填充。这个JavaScript如何干扰?一旦我使用这个对象填充了视图范围的bean的属性,它从flash范围中移除应该没有关系,对吗?仅供参考,如果我只删除JavaScript代码并保留其他所有内容,当我按下按钮提交时,它会恢复正常工作。

表#为someRequestScopedBean.Method 1

<h:form> 
    ... bunch of form objects ... 
    <h:commandButton "Start New" action="#{someRequestScopedBean.someMethod"/> 
    </h:form> 

代码:

public String someMethod() { 
     // bunch of logic here 
     FacesContext.getCurrentInstance() 
      .getExternalContext() 
       .getFlash() 
        .put("myFlashObj", myFlashObj); 
     return "form2?faces-redirect=true"; 
    } 

视图作用域在形式2中使用的豆:

@ManagedBean 
    @ViewScoped 
    public class someViewScopedBean { 
     //bunch of properties here 

     @PostConstruct 
     public void initialize() { 
      this.myObject = (MyObject) FacesContext.getCurrentInstance() 
          .getExternalContext() 
          .getFlash() 
          .get("myFlashObject"); 
     public void saveDraft() { 
      // save to database 
     } 
    } 

形式2页:

<h:outputScript library="javax.faces" name="jsf.js"/> 
    <h:form id="myForm"> 

     ... whole bunch of fields here ... 

     ... real button for user to submit ... 
     <h:commandButton value="Submit myForm" 
         action="#{someViewScopedBean.save}" /> 

     ... hidden button for auto-save by javascript ... 
     <h:commandLink id="hiddenSaveDraft" style="display: none;" 
         action="#{someViewScopedBean.saveDraft}" > 
       <f:ajax execute="@form" /> 
     </h:commandLink> 

     <script> 
      function saveDraft() { 
       document.getElementById('qForm:hiddenSaveDraft').onclick(); 
       window.setTimeout('saveDraft()',15000); 
      } 
      saveDraft(); 
     </script> 

    </h:form> 

回答

1

我想出了最终的解决方案,以及我第一次实施它的问题的原因。它不得不在JavaScript被解雇时做。脚本代码在我放置<script></script>块的确切点上被触发,该块在页面完全加载之前,可能在DOM完成之前。这导致了各种恶心,包括重复调用@PostConstruct

我通过使用JavaScript事件侦听器在页面完全加载时触发来修复它。这很重要,因为我正在使用facelets模板,并且我无权访问<h:body onload=属性。听众是一个有用和优雅的解决方案。脚本块可以放在页面的任何位置。以下是脚本块的样子:

<script> 

    function saveDraft() { 
     document.getElementById('qForm:saveDraft').onclick();  
     window.setTimeout(saveDraft,300000); 
    } 

    function initSaveTimer(e) { 
     window.setTimeout(saveDraft,300000); 
    } 

    this.addEventListener("load",initSaveTimer,true); 

    </script> 

这将每5分钟调用一次隐藏按钮来保存表单。

+0

这是解决不同于最初问题的问题的解决方案。 – BalusC 2012-04-04 15:24:06

+0

嗨@巴鲁斯,不完全。它解决了我最初的问题,即如何自动调用save方法。当我遇到JavaScript问题时,我实际上是在尝试实施您的建议。我是新来的;如果我没有正确处理这种情况,我有兴趣学习更好的方法。顺便说一下,你的原始答案发生了什么? – tcprogrammer 2012-04-04 20:13:56

1

由于您记下了Javascript作为您的一个标签,我假设您将客户端代码Javascript合并到了您的应用中。

首先使用隐藏<h:commandButton/>或隐藏< h:inputText/>(我用的情况后,我需要保存关于某个变量的一些信息)

在您提交加入其中的一个形式:

<h:commandButton style="display:none" id="clickme"> 
    <f:ajax execute="@form"> 
</h:commandButton> 

<h:inputText style="display:none" id="changeme"> 
    <f:ajax execute="@form"> 
</h:inputText> 

在你Javascript代码添加此代码可以单击或更改:

setInterval(function() { 
    document.getElementById("clickme").onclick(); 

}, 3000); // update every 3 seconds 

setInterval(function() { 
    document.getElementById("changeme").onchange(); 
}, 3000); // update every 3 seconds 

两者都可以正常工作。只要确保它们在您正在更新的表单中。