2014-06-23 20 views
5

這個問題可能更多的是「概念」或「我不懂JSF」的類型。設置操作的非法語法:如何判斷JSF我不需要「設置器」

我的場景: 我有一個JSF頁面(index.xhtml),我使用p:accordionPanel(但我認爲它不是什麼重要的組件)。我想要做的是設置它的activeIndexes

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever')}"> 
// bla bla... 
</p:accordionPanel> 

而且在支持bean(簡體)方法:

public String getActiveIndexesForSections(String holderName){ 
    String activeSections = ""; 
    for(Section s : sectionMap.get(holderName)){ 
     if (s.isActive()) 
     //add to the string 
    } 
    return activeSections; 
} 

現在,這只是正常的普通頁面加載。

但如果我點擊一個p:commandButton(與ajax=false)(或其他任何這「將」數據回我猜的服務器) - 我得到以下異常:

/WEB-INF/tags/normalTextSection.xhtml @8,112 activeIndex="#{myController.getActiveIndexesForSections(name)}": Illegal Syntax for Set Operation 
// bla.. 
Caused by: javax.el.PropertyNotWritableException: Illegal Syntax for Set Operation 

一些谷歌上搜索/閱讀後錯誤消息,我發現我需要一個setter

首先:我不想要一個setter - 我真的需要一個嗎?還是有辦法告訴JSF我不想要這個「行爲」。

第二次我意識到提供setter並不容易,因爲我的方法有一個參數(所以public void setActiveIndexesForSections(String name, String activeIndexes)public void setActiveIndexesForSections(String name)將不起作用)。 我到底來到得到的是:

創建(通用) 「僞屬性類」:

// just a dummy class since the class is recreated at every request 
public class Property<T> implements Serializable { 

    private T val; 

    public Property(T val) { 
     this.val= val; 
    } 

    public T getVal() { 
     return val; 
    } 

      //no need to do anyhting 
    public void setVal(T val) { 
    } 
} 

更改bean的方法:

public Property<String> getActiveIndexesForSections(String holderName){ 
    String activeSections = ""; 
    for(Section s : sectionMap.get(holderName)){ 
     if (s.isActive()) 
     //add to the string 
    } 
    return new Property<String>(activeSections); 
} 

,並調用它從index.xhtml

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever').val}"> 
// bla bla... 
</p:accordionPanel> 

這個工程,但顯然是一個醜陋的黑客/窩rkaround。

處理這種情況的正確方法是什麼?或者我在做什麼完全錯誤?

回答

17

需要使用setter來記住表單提交時的活動索引。基本上,您需要將它作爲值表達式(使用屬性)綁定,而不是作爲方法表達式(如操作方法),也不要綁定到不可修改的集合(如activeIndex="#{param.tab}")。完全像輸入值一樣。從技術上講,你的確在做「完全錯誤」;)

然而,要求是理解的。考慮到你對已更改的活動索引並不感興趣,因此想要將它們重置爲每個表單提交的默認值,那麼可以通過在<c:set>的幫助下將結果存儲爲請求屬性來繞過它。這樣你就可以欺騙EL在請求屬性映射中設置它,而不是內部bean屬性。

<c:set var="activeIndex" value="#{myController.getActiveIndexesForSections('whatever')}" scope="request" /> 
<p:accordionPanel multiple="true" activeIndex="#{activeIndex}"> 
    <!-- bla bla... --> 
</p:accordionPanel> 

在幕後,它將基本上做到externalContext.getRequestMap().put("activeIndex", value)作爲二傳手操作,這顯然只是工作。


更新:在檢查source code of AccordionPanel component,我看到了另一個解決辦法鑑於當rendered屬性評估falseactiveIndex將不會被設置。因此,只需更改rendered屬性的行爲即可:在更新模型值階段(第4階段)期間評估false

<p:accordionPanel multiple="true" 
    activeIndex="#{myController.getActiveIndexesForSections('whatever')}" 
    rendered="#{facesContext.currentPhaseId.ordinal ne 4}"> 
    <!-- bla bla... --> 
</p:accordionPanel> 
+0

感謝你憐憫我;)你會推薦另一種方式來做到這一點 - 因爲它是「簡單」錯誤? (我不能相信的是,這個用例非常罕見,以至於沒有人(期望我)想要這麼做 - 所以我確實想知道我是否理解了這個大局...) - 也是我的'accordionPanel' s是在標籤中生成的,其中'whatever'作爲參數傳入 - 我甚至可以使用參數作爲'c:set'的'var',然後作爲'accordionPanel'的'activeIndex'嗎?如果是這樣如何? –

+1

在這個特定情況下,正確的方法是返回一個自定義的'Map'實現。不,你不能在'var'屬性中使用EL,所以標籤文件會很糟糕。無論如何,在檢查''的源代碼之後,我發現了另一種解決方法,它可以在tagfiles中更好地重用。查看答案更新。 – BalusC

+0

謝謝。明天將嘗試這個&也是'定製'地圖。如果它的作品接受+「賞金」你:) –

相關問題