2013-06-18 4 views
1

Я пытаюсь захватить старое/новое значение для некоторой проверки бизнеса. Для этого ValueChangeListener показался хорошим выбором. Он отлично справился с h: selectOneMenu, однако он не вызывается при использовании с встроенным композитным компонентом с компонентом Backing. Любая идея, что я делаю неправильно?JSF ValueChangeListener не вызывается для составного компонента с опорным компонентом

Одна вещь, чтобы добавить это, при удалении атрибута ComponentType из state.xhtml, то valueChangeListener работает, как ожидалось ...

Компонент:

<!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:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:composite="http://java.sun.com/jsf/composite"> 

    <composite:interface displayName="state" componentType="com.company.dept.system.ui.address.State" shortDescription="State Information Display/Input Component"> 
     <composite:attribute name="value" type="java.lang.String" required="true" shortDescription="The value of the component" />  
     <composite:editableValueHolder name="state" />    
    </composite:interface> 

    <composite:implementation> 
    <div id="#{cc.clientId}"> 

      <h:selectOneMenu id="state" value="#{cc.attrs.value}"> 
       <f:selectItem itemLabel="(select)" noSelectionOption="true"/> 
       <f:selectItems var="item" itemLabel="#{item.displayValue}" value="#{cc.states}" /> 
      </h:selectOneMenu>  

    </div> 

    </composite:implementation> 
</html> 

Поддерживающий компонент

@FacesComponent("com.company.dept.system.ui.address.State") 
public class State extends UIInput implements NamingContainer { 

    private List<com.company.dept.policy.enums.State> states; 

    @Override 
    public String getFamily() { 
     return UINamingContainer.COMPONENT_FAMILY; 
    } 

    /** 
    * Prepare the list of states to display 
    */ 
    public List<com.company.dept.policy.enums.State> getStates(){ 

     if (states != null) { 
      return states; 
     } 

     states = new ArrayList<com.company.dept.policy.enums.State>();    
     for (com.company.dept.policy.enums.State st : com.company.dept.policy.enums.State.values()) { 
      if(!st.equals(com.company.dept.policy.enums.State.NWNORWAY) && !st.equals(com.company.dept.policy.enums.State.UNKNOWN) && !st.equals(com.company.dept.policy.enums.State.TTTRUST_TERRITORY_AND_GUAM)) {    
       states.add(st); 
      } 
     } 
     Collections.sort(states,new StateNameComparator()); 

     return states; 
    } 

} 

Приемник изменения стоимости

public class ClientValueChangeListener implements ValueChangeListener { 

    @Override 
    public void processValueChange(ValueChangeEvent event) 
      throws AbortProcessingException { 
     System.out.println("*****************************"); 
     System.out.println("VALUE CHANGE LISTENER. OLD=" + event.getOldValue() + " - NEW=" + event.getNewValue()); 
     System.out.println("*****************************"); 
     } 
} 

потреаяся страница:

<h:form> 
    <address:state value="#{testPage.state}"> 
     <f:valueChangeListener type="com.company.dept.system.ui.clientinformation.ClientValueChangeListener" for="state"/> 
    </address:state> 
    <h:commandButton id="submitButton" value="Test" action="#{testPage.act}"/>   
</h:form> 
+0

Какая версия JSF/версия? Что делать, если вы явно указываете ''? – BalusC

+0

Использование Mojarra 2.1.13 на jBoss EAP 6. Я попытался установить цели = "state" на editableValueHolder, но это не повлияло. –

+0

Теперь я вижу, что ваш компонент поддержки распространяется от 'UIInput'. Я бы сказал, просто избавьтесь от этого. Я отправил ответ. – BalusC

ответ

2

Это потому, что ваш компонент поддержки простирается от UIInput. Слушатель изменения значения применяется к самому компоненту поддержки, а не к дочернему компоненту составной реализации.

Ваше конкретное функциональное требование не совсем ясно, но на основе предоставленной информации вы можете безопасно заменить extends UIInput implements NamingContainer на extends UINamingContainer (и избавиться от переопределения getFamily()).

Если вы действительно хотите, чтобы ваш поддерживающий компонент расширялся от UIInput, вы должны делегировать переданное значение, локальное значение и значение компонента поддержки всем компонентам выпадающего дочернего элемента, но это делает дизайн технически мало смысл.

+0

В этом была проблема! Вместо этого расширенный UINamingContainer, и слушатель начал работать! Благодаря! BTW, деловое требование имеет раскрывающееся меню штата с расфасованным внешним видом. –

+0

Добро пожаловать. Если вы когда-либо намереваетесь использовать ** несколько ** компонентов ввода в своем составе и намереваться получить/установить его с помощью свойства ** single ** value, то вы действительно должны позволить своему компоненту backing от 'UIInput', но это требует очевидно, немного больше работы. Но имейте в виду, что в таком случае в любом случае было бы мало смысла ориентировать определенный дочерний компонент ввода с помощью прослушивателя изменения стоимости. – BalusC

+0

У меня есть другие компоненты, которые расширяют UIInput и переопределяют encodeBegin, getSubmittedValue и getConvertedValue. Было много работы по их объединению, и я до сих пор не совсем понимаю, что делают все методы и какие другие методы доступны. Можете ли вы порекомендовать расширенный учебник, в котором объясняются компоненты резервного копирования? –