最近在做項目的時候,碰到了一個JSF的問題,就是輸入組件設置了readonly屬性之后,提交的時候就得不到該組件的值了,仔細研究了一番,才找到原因和解決方法。
具體的現象是這樣的,一個輸入框需要設置為不能讓用戶更改,但可以通過javascript改變,改變后提交,則在服務器端得到改變后的值進行處理。這種需求應該也是非常常見的,可是在用JSF實現時,卻碰到了問題。具體JSF代碼如下:
1 <h:form id="theForm">
2 <h:inputText id="theValue" readonly="true" value="#{readonlyBean.theValue}"/>
3 <h:commandButton value="Submit" action="#{readonlyBean.submit}"/>
4 <af:outputText value="Click" onclick="editReadonly();"/>
5 </h:form>
第一個<h:inputText>就是我們要研究的對象,第二個<h:commandButton>是提交的按鈕,第三個<af:outputText>是為了有一個地方可以點擊,點擊后調用javascript來改變第一個組件的值,至于af是來自于ADF,ADF是Oracle的JSF實現,提供了更多的功能,為什么不用<h:outputText>呢?因為很奇怪,標準的JSF組件<h:outputText>竟然不接受onclick事件??傊?,調用的editReadonly()的javascript代碼如下:
1 function editReadonly() {
2 document.getElementById('theForm:theValue').value = "ABCD";
3 }
在服務器端,Managed Bean中的代碼如下:
1 public class ReadonlyBean {
2 private String theValue = "XYZ";
3
4 public void setTheValue(String aValue) {
5 this.theValue = aValue;
6 }
7
8 public String getTheValue() {
9 return theValue;
10 }
11
12 public String submit() {
13 System.out.println( this.getTheValue() );
14
15 return null;
16 }
17 }
以上代碼就是開始給theValue以初始值XYZ,然后在提交時打印出theValue的值。
運行時,首先點擊"Click",看到頁面上的只讀輸入組件的值變成了ABCD,然后提交,發現服務器端打印出來的值仍然是XYZ,沒有得到該輸入框的新值。
然而如果直接用HTML來完成這一功能時,頁面上有一個readonly的輸入框,提交到一個servlet,在servlet中從request中得到該輸入框的值打印出來,那么在用javascript改變了該輸入框的值后,打印出來的值是變化之后的值,說明標準的HTML的readonly的值是會提交的。
怎么會這樣呢?JSF的輸入組件設為readonly之后似乎不提交自己的值?為了解決這一問題,首先查看JSF最后生成的HTML頁面的源代碼,似乎沒有任何問題,也是解析成一個標準的HTML的<input>,那說明在頁面這個值是確實存在,也被提交給JSF框架,只是在后臺處理時JSF忽略了該組件,這非常奇怪,為什么要采取這個和標準HTML不一致的行為?是不是當前使用的JSF的實現的問題?在換了好幾個JSF的實現之后(Oracle的實現,MyFaces的實現,Sun的RI實現),結果都是一樣,看來只有看看實現的源代碼才能找到原因了。
下載了MyFaces 1.2的源代碼,然后首先找到HtmlInputText的renderer:HtmlTextRenderer,因為提交時首先調用組件的renderer的docode方法來解析request的參數。然后發現該類是擴展了HtmlTextRendererBase,之后發現是調用了HtmlRendererUtils.decodeUIInput()來解析的,在該方法的一開始,就發現如下語句:
1 if(isDisabledOrReadOnly(component))
2 return;
這里充分說明了在JSF中readonly和disable一樣,都是不會將參數提交給后臺的。
原因找到了,那為什么JSF會采用這種方式。解釋可能要回到JSF是一個組件的框架這一點上來。因為<h:inputText>是一個組件,那一個只讀的組件是不是就應該不能改變其值呢?
最后則說一下怎么繞過這一限制,從而實現我們一開始想要的功能。實現的方法則只能是加一個隱藏的輸入組件,在javascript改變只讀輸入框時,也同時改變該隱藏的輸入組件的值,那么提交后就能得到這個隱藏輸入組件的值。
posted on 2009-02-24 10:22
飛馬涼 閱讀(1680)
評論(1) 編輯 收藏