2014-04-02 56 views
0

我一直在問重構下面的代碼,它的工作原理:豆範圍損失從未被稱爲

<a4j:commandButton type="image" 
    image="/someImage.gif" 
    action="#{SomeViewController.someDeleteAction}" 
    onclick="return confirm('#{msg['a.message']}');" 
    render="someDataTableWithItems"> 
    <f:setPropertyActionListener 
     target="#{SomeViewModel.selectedItem}" value="#{item}" /> 
</a4j:commandButton> 

..to它允許使用自定義彈出替代確認行動。該片段嵌入在rich:dataTable組件內的列中。 #{item}是分配給此按鈕所在行的對象的引用(在dataTable中定義爲var="item")。

我決定做一個JSF複合組件(我的第一個組件)有一些我可以重用的東西。它基於此answer by elias

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:a4j="http://richfaces.org/a4j" 
    xmlns:rich="http://richfaces.org/rich" 
    xmlns:cc="http://java.sun.com/jsf/composite"> 
<cc:interface> 
    <cc:attribute name="message" default="#{msg['a.default.message']}" /> 
    <cc:attribute name="header" 
     default="#{msg['a.default.header']}" /> 
    <cc:attribute name="action" required="true" 
     method-signature="java.lang.String action()" /> 
    <cc:attribute name="actionListener" required="false" 
     method-signature="java.lang.String action()" /> 
    <cc:attribute name="value" default="Send" /> 
    <cc:attribute name="cancelBtn" default="#{msg['a.default.cancel']}" /> 
    <cc:attribute name="confirmBtn" default="#{msg['a.default.ok']}" /> 
    <cc:attribute name="render" default="@form" /> 
    <cc:attribute name="type" default="submit" /> 
    <cc:attribute name="image" required="false"/> 
    <cc:attribute name="tooltip" required="false" /> 
</cc:interface> 
<cc:implementation> 
    <a4j:commandButton type="#{cc.attrs.type}" rendered="#{empty cc.attrs.actionListener and not empty cc.attrs.image}" 
     image="#{cc.attrs.image}" value="#{cc.attrs.value}" 
     oncomplete="#{rich:component('somePopup')}.show()"> 
     <rich:tooltip followMouse="false" showDelay="1000" rendered="#{not empty cc.attrs.tooltip}"> 
      #{cc.attrs.tooltip} 
     </rich:tooltip> 
    </a4j:commandButton> 
    <a4j:commandButton type="#{cc.attrs.type}" rendered="#{not empty cc.attrs.actionListener and not empty cc.attrs.image}" 
     actionListener="#{cc.attrs.actionListener}" 
     image="#{cc.attrs.image}" value="#{cc.attrs.value}" 
     oncomplete="#{rich:component('somePopup')}.show()"> 
     <rich:tooltip followMouse="false" showDelay="1000" rendered="#{not empty cc.attrs.tooltip}"> 
      #{cc.attrs.tooltip} 
     </rich:tooltip> 
    </a4j:commandButton> 
    <a4j:commandButton type="#{cc.attrs.type}" rendered="#{empty cc.attrs.actionListener and empty cc.attrs.image}" 
     value="#{cc.attrs.value}" 
     oncomplete="#{rich:component('somePopup')}.show()"> 
     <rich:tooltip followMouse="false" showDelay="1000" rendered="#{not empty cc.attrs.tooltip}"> 
      #{cc.attrs.tooltip} 
     </rich:tooltip> 
    </a4j:commandButton> 
    <a4j:commandButton type="#{cc.attrs.type}" rendered="#{not empty cc.attrs.actionListener and empty cc.attrs.image}" 
     actionListener="#{cc.attrs.actionListener}" value="#{cc.attrs.value}" 
     oncomplete="#{rich:component('somePopup')}.show()"> 
     <rich:tooltip followMouse="false" showDelay="1000" rendered="#{not empty cc.attrs.tooltip}"> 
      #{cc.attrs.tooltip} 
     </rich:tooltip> 
    </a4j:commandButton> 
    <rich:popupPanel id="somePopup" 
     header="#{cc.attrs.header}" autosize="true" resizeable="false"> 
     <p>#{cc.attrs.message}</p> 
     <a4j:commandButton action="#{SomeViewController.someDeleteAction}" <!-- It should be #{cc.attrs.action} but I just put this for debug --> 
      value="#{cc.attrs.confirmBtn}" render="#{cc.attrs.render}" 
      oncomplete="#{rich:component('somePopup')}.hide()"> 
      <cc:insertChildren /> 
     </a4j:commandButton> 
     <h:commandButton value="#{cc.attrs.cancelBtn}" 
      onclick="#{rich:component('somePopup')}.hide(); return false;" /> 
    </rich:popupPanel> 
</cc:implementation> 
</html> 

..和取代先前a4j:commandButton本:

<my:buttonConfirm type="image" id="someID" 
    image="/someImage.gif" 
    action="#{SomeViewController.someDeleteAction}" 
    message="#{msg['a.confirmation.message']}" 
    render="someDataTableWithItems" 
    tooltip="#{msg['a.tooltip.message']}"> 
    <f:setPropertyActionListener for="someID" 
     target="#{SomeViewModel.selectedItem}" value="#{item}" /> 
</my:buttonConfirm> 

的彈出窗口,你可以取消行動,但它確認時,SomeViewModel再次重新實例化,失去範圍中的前一個bean。

範圍是自定義視圖範圍從here

了後來我改變了模型的範圍,這一個:

@Component("SomeViewModel") 
@ViewScoped 

雖然我試圖用@ManagedBean代替@Component,應用了我自動裝配錯誤,所以我離開了@Component。範圍現在保留。 我不知道在這種方式下JSF和Spring註釋的混合是否會產生其他後果。

然而SomeViewModel範圍現在是精細,f:setPropertyActionListener目標從未設定和動作#{SomeViewController.someDeleteAction}從未被調用。我一直無法調試(不確定在哪裏放置斷點來查看中間發生了什麼)。

在此先感謝您的幫助。

回答

0

在嘗試了一些建議並對我自己進行了一些研究之後,我得出結論,在rich:popupPanel中使用a4j:commandButton時存在某種問題。沒有調用Action方法,並且沒有設置在f:setPropertyActionListener上定義的屬性。我一直無法找出那裏正在迷失的東西。

我在互聯網上看到了一個彈出式窗口中的示例,因此我不確定這是否是由我的任何依賴引起的。我使用jsf-api 2.1.19,jsf-impl 2.1.19-jbossorg-1和richfaces 4.3.5.Final。

這是我終於做的解決方法。我希望這可以幫助任何人以同樣的問題,我有:

confirmButton.xhtml

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:a4j="http://richfaces.org/a4j" 
    xmlns:rich="http://richfaces.org/rich" 
    xmlns:cc="http://java.sun.com/jsf/composite"> 
<cc:interface> 
    <cc:attribute name="message" 
     default="Some message" /> 
    <cc:attribute name="header" 
     default="Some header" /> 
    <cc:attribute name="cancelBtn" default="No" /> 
    <cc:attribute name="confirmBtn" default="Yes" /> 
    <cc:attribute name="type" default="submit" /> 
    <cc:attribute name="icon" required="false" /> 
    <cc:attribute name="image" required="false" /> 
    <cc:attribute name="action" 
     targets="popupConfirmButton" /> 
    <cc:actionSource name="confirmListeners" 
     targets="popupConfirmButton" /> 
</cc:interface> 
<cc:implementation> 
    <a4j:commandButton type="#{cc.attrs.type}" 
     image="#{cc.attrs.image}" 
     oncomplete="#{rich:component('popupConfirm')}.show()"> 
    </a4j:commandButton> 
    <a4j:commandButton id="popupConfirmButton" 
     style="visibility: hidden;" render="#{cc.attrs.render}"> 
    </a4j:commandButton> 
    <rich:popupPanel id="popupConfirm" header="#{cc.attrs.header}" 
     autosized="true" width="475" resizeable="false"> 
     <f:facet name="controls"> 
      <h:outputLink value="#" 
       onclick="#{rich:component('popupConfirm')}.hide(); return false;" /> 
     </f:facet> 
     <h:panelGrid columns="2"> 
      <h:graphicImage value="#{cc.attrs.icon}" height="64" width="64" /> 
      <p>#{cc.attrs.message}</p> 
     </h:panelGrid> 
     <br /> 
     <div align="right"> 
      <a4j:commandButton value="#{cc.attrs.confirmBtn}" 
       onclick="#{rich:element('popupConfirmButton')}.click(); 
       #{rich:component('popupConfirm')}.hide();" /> 
      &#160; 
      <h:commandButton value="#{cc.attrs.cancelBtn}" 
       onclick="#{rich:component('popupConfirm')}.hide(); return false;" /> 
     </div> 
    </rich:popupPanel> 
</cc:implementation> 
</html> 

部件使用情況

<my:confirmButton type="image" image="someButtonImage.gif" 
    icon="someWarningImage.gif" 
    action="#{SomeViewController.doStuff}" 
    message="Some message" 
    render="someComponentID"> 
    <f:setPropertyActionListener for="confirmListeners" 
     target="#{SomeViewModel.someProperty}" value="foo" /> 
</my:confirmButton> 
1

<f:setPropertyActionListener>不附加到組件id,而是附加到ActionSource。請參閱this answer瞭解如何操作。

編輯:

的基本上代替<f:setPropertyActionListener for="buttonId">你會被<f:setPropertyActionListener for="source">

<cc:interface> 
    <cc:actionSource name="source" targets="buttonId" /> 
    … 
</cc:interface> 
<cc:implementation> 
    <a4jcommandButton id="buttonId" … /> 
</cc:implementation> 

並指向它。

+0

我不知道如何實現您建議。 – jplatasv

+0

@NiKoLai_我編輯了答案 – Makhiel

+0

感謝您的幫助,@Makhiel。我已經嘗試了與你解釋的相同的方式,但是這兩個設置者都沒有被解僱,也沒有被定義爲動作的函數被調用。完成後,彈出窗口甚至沒有關閉。我認爲有些東西在視圖中迷失了,因爲我在javascript控制檯上看到這條消息:'Uncaught TypeError:無法調用方法'隱藏'未定義'。該隱藏函數可能是在'a4j:commandButton'的'oncompletion'屬性上調用的'hide'彈出函數。任何其他的想法可能會發生什麼?提前致謝。 – jplatasv