2012-05-23 26 views
5

在我的基於JSF 2的應用程序中,我有一個表單(包括其他UI組件)中的一些複選框。經過驗證錯誤後續ajax請求從UI組件獲取值而不是從豆

在複選框上,我已經註冊了ajax請求,它們在被檢查時觸發。 ajax請求實際上只會更新後臺bean中另一個複選框的值。 因此,其他複選框也會被檢查(當它被重新渲染時 - 因爲它將在渲染響應階段從支持bean中獲取更新值)。

這工作正常,直到整個表單被提交併發生驗證錯誤。 然後,ajax請求仍然可以工作並更改輔助bean上的值,但是在重新呈現更新複選框的階段,其值不是從支持bean中獲取的,而是從ComponentStateHelper類中獲取的緩存值中獲取的。

據我瞭解,這是用於JSF 2的新功能,只存儲對組件樹的部分更改。

我不明白的是:這與驗證階段有什麼關係?爲什麼當驗證發現錯誤時,我的複選框在StateHelper類中存在緩存值?

回答

4

這是一個已知問題,並在this answer中進行了深入解釋。簡而言之,問題是由於要由<f:ajax render>呈現但未被<f:ajax execute>執行的無效組件與原始提交值一起保持無效狀態。當JSF呈現輸入組件時,JSF將首先檢查提交的值是不是null然後顯示它,否則它將顯示模型值。您基本上需要重置要呈現的輸入組件的提交值,但這些輸入組件並未由ajax執行。

要做到這一點,你可以使用一個ActionListener基本上執行以下操作:

UIViewRoot viewRoot = context.getViewRoot(); 
PartialViewContext partialViewContext = facesContext.getPartialViewContext(); 
Set<EditableValueHolder> inputs = new HashSet<EditableValueHolder>(); 

// First find all to be rendered inputs and add them to the set. 
findAndAddEditableValueHolders(partialViewContext.getRenderIds(), inputs); 

// Then find all executed inputs and remove them from the set. 
findAndRemoveEditableValueHolders(partialViewContext.getExecuteIds(), inputs); 

// The set now contains inputs which are to be rendered, but which are not been executed. Reset them. 
for (EditableValueHolder input : inputs) { 
    input.resetValue(); 
} 

這已被報告爲JSF issue 1060和完整,可重複使用的解決方案已經在OmniFaces庫被實現爲ResetInputAjaxActionListener(源代碼here和展示演示here)。

+0

非常感謝您的回答。無論如何,我已經將你的omnifaces庫包含在我的項目中(對於'FullAjaxExceptionHandlerFactory')。所以很容易在我的'faces-config.xml'文件中包含'ResetInputAjaxActionListener'。 但是這只是在'InvokeApplicationPhase'中調用的,它沒有被我的ajax請求命中。我的ajax請求由一個''觸發,並在那裏由''觸發。 但我會仔細看看這個。我只是很快嘗試了你的建議。 – Jens

+0

它沒有被擊中?你確定?編輯faces-config後,您可能需要重新啓動服務器。 – BalusC

+0

我確實重新啓動了它,並添加了omnifaces的源並設置了一個斷點以查看它是否被命中。它確實遇到了常規請求,但不會受到由選擇複選框觸發的ajax請求。 – Jens