Pregunta

I am having a pretty frustrating time trying to get values across components. I am trying to do an address component that I can reuse, once for a residential address and once for a postal address. There is a selectOneCheck box which allows the user to specify that the residential address is the same as the postal address. I would like the the values of the first(residential address) component copied to the values of the second (postal address)component, then to disable the second component.

Here is my code for the composite component:

<composite:interface>




    <composite:attribute name="addressLine1" required="true"
        targets="addressLine1Text" />
    <composite:attribute name="addressLine2" required="false"
        targets="addressLine2Text" />
    <composite:attribute name="addressLine3" required="false"
        targets="addressLine3Text" />
    <composite:attribute name="city" required="true" targets="cityText" />
    <composite:attribute name="state" required="true" targets="stateText" />
    <composite:attribute name="postCode" required="true"
        targets="postCodeText" />
    <composite:attribute name="styleClass" required="true" />

    <composite:attribute name="disabled" required="true" />

    <composite:attribute name="addressLine1Label" required="false"
        targets="addressLine1Label" />
    <composite:attribute name="addressLine2Label" required="false"
        targets="addressLine2Label" />
    <composite:attribute name="addressLine3Label" required="false"
        targets="addressLine3Label" />
    <composite:attribute name="cityLabel" required="false"
        targets="cityLabel" />
    <composite:attribute name="stateLabel" required="false"
        targets="stateLabel" />
    <composite:attribute name="postCodeLabel" required="false"
        targets="postCodeLabel" />


<composite:implementation>
 <composite:renderFacet name="heading"/>

    <h:panelGrid columns="3">
        <h:outputLabel id="addressLine1Label" for="addressLine1Text"
            value="#{cc.attrs.addressLine1Label}" />
        <h:inputText id="addressLine1Text" value="#{cc.attrs.addressLine1}" >
        </h:inputText>
        <h:message for="addressLine1Text" id="addressLine1Message" />


        <h:outputLabel id="addressLine2Label" for="addressLine2Text"
            value="#{cc.attrs.addressLine2Label}" />
        <h:inputText id="addressLine2Text" value="#{cc.attrs.addressLine2}">
        </h:inputText>
        <h:message for="addressLine2Text" id="addressLine2Message" />



        <h:outputLabel id="addressLine3Label" for="addressLine3Text"
            value="#{cc.attrs.addressLine3Label}" />
        <h:inputText id="addressLine3Text" value="#{cc.attrs.addressLine3}">
        </h:inputText>
        <h:message for="addressLine3Text" id="addressLine3Message" />



        <h:outputLabel id="cityLabel" for="cityText"
            value="#{cc.attrs.cityLabel}" />
        <h:inputText id="cityText" value="#{cc.attrs.city}">
        </h:inputText>
        <h:message for="cityText" id="cityMessage" />


        <h:outputLabel id="stateLabel" for="stateText"
            value="#{cc.attrs.stateLabel}" />
        <h:inputText id="stateText" value="#{cc.attrs.state}">
        </h:inputText>
        <h:message for="stateText" id="stateMessage" />


        <h:outputLabel id="postCodeLabel" for="postCodeText"
            value="#{cc.attrs.postCodeLabel}" />
        <h:inputText id="postCodeText" value="#{cc.attrs.postCode}">
        </h:inputText>
        <h:message for="postCodeText" id="postCodeMessage" />

    </h:panelGrid>
</composite:implementation>

Here is the the component in use :

<add:address 
                        id="residentialAddress" styleClass="bold"
                        addressLine1="#{registrationBean.residentialAddress.addressLine1}"
                        addressLine2="#{registrationBean.residentialAddress.addressLine2}"
                        addressLine3="#{registrationBean.residentialAddress.addressLine3}"
                        city="#{registrationBean.residentialAddress.city}"
                        state="#{registrationBean.residentialAddress.state}"
                        postCode="#{registrationBean.residentialAddress.postCode}"
                        addressLine1Label="#{msgs.addressLine1}"
                        addressLine2Label="#{msgs.addressLine2}"
                        addressLine3Label="#{msgs.addressLine3}"
                        cityLabel="#{msgs.city}"
                        stateLabel="#{msgs.state}" 
                        postCodeLabel="#{msgs.postCode}"    
                        >

                        <f:facet name="heading">
                            <h:outputLabel value="#{msgs.residentialAddress}" />
                        </f:facet>

                            <f:converter for="add" converterId="myConvertor"/>

                    </add:address>

Here is the selectOneRadioButton:

                        <p:selectBooleanCheckbox 
                        id="sameAsResidentialAddress" 
                        itemLabel="#{msgs.sameAsResidentialAddress}"
                        valueChangeListener="#{registrationBean.sameAsResidentialAddress}" 

                            >
                    <f:ajax execute="@form"  render="postalAddress">

                    </f:ajax>
                    </p:selectBooleanCheckbox>
                    <h:message for="sameAsResidentialAddress"/>

Here is the component being resused for postal address:

<add:address id="postalAddress" styleClass="bold"
                        addressLine1="#{registrationBean.residentialAddress.addressLine1}"
                        addressLine2="#{registrationBean.postalAddress.addressLine2}"
                        addressLine3="#{registrationBean.postalAddress.addressLine3}"
                        city="#{registrationBean.postalAddress.city}"
                        state="#{registrationBean.postalAddress.state}"
                        postCode="#{registrationBean.postalAddress.postCode}"
                        addressLine1Label="#{msgs.addressLine1}"
                        addressLine2Label="#{msgs.addressLine2}"
                        addressLine3Label="#{msgs.addressLine3}" cityLabel="#{msgs.city}"
                        stateLabel="#{msgs.state}" postCodeLabel="#{msgs.postCode}"
                        rendered="#{!registrationBean.same}">

                        <f:facet name="heading">
                            <h:outputLabel value="#{msgs.postalAddress}" />
                        </f:facet>


                        <f:converter for="add" converterId="myConvertor"/>



                    </add:address>

The java code are a POJOs for Address and Registration. Registration has a valueChangeListener that sets a boolean to true if the sameAsResidentialAddress selectOneRadio is checked.

    public void sameAsResidentialAddress(ValueChangeEvent event){
       setSame((Boolean)event.getNewValue());
   }

These components are on the same form named registration with no prepended id to them.

it roughly looks like this:

<h:form id="Registration">
   <p:wizard>
   <p:tab id ="address" title="Your Addresses">
   <p:panel id="addresses">
    <add:address id= "residentialAddress"> 
      ...
     </add:address>   

      <p:selectBooleanCheckbox id="sameAsResidentialAddress">
        ...
      </p:selectBooleanCheckbox> 

    <add:address id= "postalAddress"> 
      ...
     </add:address>     
   </p:panel>
   </p:tab>
   </p:wizard>
</h:form>

I have tried my best to make my request as understandable as possible, and I hope you guys can understand what I am after. Please help me.

¿Fue útil?

Solución 2

The problem was I did not completely understand the JSF lifecycle, I was updating my values the APPLY_REQUEST_VALUES phase instead of the INVOKE_APPLICATION phase. Also setting the postal address to the same object as the residential address is a bad idea because it end up with me not being able to update either one without affecting the other.

This works better.

public void sameAsResidentialAddress(ValueChangeEvent event) throws AbortProcessingException{ FacesContext context = FacesContext.getCurrentInstance();

    if(context.getCurrentPhaseId() != PhaseId.INVOKE_APPLICATION){
        event.setPhaseId(PhaseId.INVOKE_APPLICATION);
        event.queue();
        return;
    }
    if ((Boolean)event.getNewValue()){

        this.setSame(true);
        this.getPostalAddress().setAddressLine1(getResidentialAddress().getAddressLine1());
        this.getPostalAddress().setAddressLine2(getResidentialAddress().getAddressLine2());
        this.getPostalAddress().setAddressLine3(getResidentialAddress().getAddressLine3());
        this.getPostalAddress().setCity(getResidentialAddress().getCity());
        this.getPostalAddress().setState(getResidentialAddress().getState());
        this.getPostalAddress().setPostCode(getResidentialAddress().getPostCode());
        System.out.println("Value was true");
        System.out.println("Postal Address " + getPostalAddress());
        System.out.println("Residential Address " + getResidentialAddress());
    }else{
        setPostalAddress(new Address());
    }

}

Otros consejos

In the value change listener of the boolean check box you have to populate the postal address object which you are not doing. If both postal address and residential address are of the same type Address then you have to do

public void sameAsResidentialAddress(ValueChangeEvent event){
   if((Boolean)event.getNewValue()) { 

      setSame((Boolean)event.getNewValue());  
      registrationBean.setPostalAddress(registrationBean.getResidentialAddress());
    }  
}  

Hope this would help.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top