2012-04-01 113 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 

兩者都可以正常工作。只要確保它們在您正在更新的表單中。