Thursday, June 21, 2012

show/hide table in jsp struts

 <logic:equal name="searchPatientFormBean" property="showPatientSearchResult" value="true">  
 <table>  
 ..data..  
 </table>  
 </logic:equal>  
where name="searchPatientFormBean" is the form bean name given in the <action>

property="showPatientSearchResult" is the attribute of form bean whose value is set to false intially.

The table will be displayed only if showPatientSearchResult=true

Customized JSF table

Problem:
To create a data table in JSF in which the first row data spans across the columns ie only one column in the first row and the second row had 8 columns and it should alternate like that. This is not possible with h:dataTable tag

Reason:
The h:dataTable tag renderds data column wise

Solution:
To create such a table with column span use jstl along with plain html and jsf components

Sample Code:
 <c:forEach items="#{HospInvProfBean.productList}" var="product" varStatus="status"> /> <tr><td colspan="8" class="genText">  
  <h:outputText value="#{product.productDescription}"/></td> </tr>  
  <tr class="dtlLineCen">  
  <td style="width: 10%;">  
 <span class="genText">Minimum</span></td>  
 <td><h:inputText size="4" value="#{product.oposMin}" converter="javax.faces.Long" converterMessage="Not a number"/></td>  
  <td><h:inputText size="4" value="#{product.aposMin}" converter="javax.faces.Long" converterMessage="Not a number" /></td>  
 <td><h:inputText size="4" value="#{product.bposMin}" required="true" /></td>              
  <td><h:inputText size="4" value="#{product.abposMin}" required="true" /></td>     
  <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.onegMin}" required="true" /></td>              
  <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.anegMin}" required="true" /></td>              
 <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.bnegMin}" required="true" /></td>             
 <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.abnegMin}" required="true" /></td></tr>             
 <tr class="dtlLineAltCen">  
 <td style="width: 10%;"><span class="genText">Optimal</span></td>            <td><h:inputText size="4" value="#{product.oposOpt}" required="true" /></td>  
  <td><h:inputText size="4" value="#{product.aposOpt}" required="true" /></td>  
  <td><h:inputText size="4" value="#{product.bposOpt}" required="true" /></td>  
 <td><h:inputText size="4" value="#{product.abposOpt}" required="true" /></td>  
  <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.onegOpt}" required="true"/></td>  
  <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.anegOpt}" required="true"/></td>  
  <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.bnegOpt}" required="true"/></td>  
  <td><h:inputText size="4" rendered="#{product.aboGroup}" value="#{product.abnegOpt}" required="true"/></td>  
 </c:forEach>  

Custom Converter Spring 2.5 / Spring webflow


1. Dispatcher Servlet configuration

 <bean id="viewResolver"  
           class="org.springframework.web.servlet.view.ResourceBundleViewResolver"  
           p:basename="views" />  
 <bean id="tilesConfigurer"  
           class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"  
           p:definitions="/WEB-INF/tiles-defs.xml" />  
 <flow:flow-builder-services id="flowBuilderServices"  
           view-factory-creator="viewFactoryCreator" conversion-service="conversionService" />  

2. Write Convert Class

java.util.Calendar to String Custom Converter / String to java.util.Calendar Custom Converter

 import java.text.DateFormat;  
 import java.text.ParseException;  
 import java.text.SimpleDateFormat;  
 import java.util.Calendar;  
 import org.springframework.binding.convert.converters.TwoWayConverter;  
 public class CalendarStringTwoWayConverter implements TwoWayConverter {  
      @Override  
      public Class getSourceClass() {  
           return Calendar.class;  
      }  
      @Override  
      public Class getTargetClass() {  
           return String.class;  
      }  
      @Override  
      public Object convertSourceToTargetClass(Object source, Class targetClass)  
                throws Exception {  
           String date = null;  
           DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");  
           if(null!=source){  
                date= dateFormat.format(((Calendar) source).getTime()).toString();  
           }  
           return date;  
      }  
      @Override  
      public Object convertTargetToSourceClass(Object target, Class sourceClass)  
                throws Exception {  
            Calendar cal = Calendar.getInstance();  
         SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");  
         try {  
                 cal.setTime(sdf.parse((String) target));  
            } catch (ParseException e) {  
                 e.printStackTrace();  
            }  
           return cal;  
      }  
 }  

3. Register Converter

 import org.springframework.binding.convert.service.DefaultConversionService;  
 import org.springframework.stereotype.Component;  
 @Component("conversionService")  
 public class ApplicationConversionService extends DefaultConversionService {  
      @Override  
      protected void addDefaultConverters() {  
           super.addDefaultConverters();  
           addDefaultAliases();  
           addConverter("calenderStringTwoWayConverter", new CalendarStringTwoWayConverter());  
           addConverter("enumStringTwoWayConverter", new EnumStringTwoWayConverter());  
           addConverter("timeStringTwoWayConverter", new TimeStringTwoWayConverter());  
      }  
 }  

Use in flow registry : Bind  properties with converter
 <view-state id="review" view="review" model="reviewModel">  
      <binder>  
           <binding property="state" converter="enumStringTwoWayConverter"/>            
           <binding property="time" converter="timeStringTwoWayConverter"/>             
           <binding property="date" converter="calenderStringTwoWayConverter"/>   
      </binder>  
 </view-state>  

This way of using named converters has been discontinued from Spring 3.0. In Spring3.0 the converters are handled in a different way.

4. Use in JSP

There is nothing special in jsp.

 <form:form name="myform" modelAttribute="reviewModel">  
      <form:input type="text" id="date" path="date" value="${date}"/>  
 </form:form>  

Single selection checkbox javascript


Javascript:

 function singleSelectCheckbox(checkbox) {  
       var cbs = document.getElementsByTagName('input');  
       for(var i=0; i < cbs.length; i++) {  
             if(cbs[i].type == 'checkbox') {  
                   if (cbs[i].id == checkbox.id) {    
             continue;  
                   }  
                   else{  
                        cbs[i].checked = false;   
                        }  
                   }  
            }  
        }  
In html page, give different ids to each checkboxes

Wednesday, May 16, 2012

Spring Webflow Popup example in JSP

Spring version: Spring webflow 2.0.3 , Spring MVC 3.0.5

1. In the parent jsp page add the following java script

 <script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js" />"> </script>  
 <script type="text/javascript" src="<c:url value="/resources/spring/Spring.js" />"> </script>  
 <script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js" />"> </script>  
 <link type="text/css" rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css" />" />  
 <script type="text/javascript">  
      Spring.addDecoration(new Spring.AjaxEventDecoration({                           
                                    elementId: 'popupbutton',  
                                    formId: 'myform',  
                                    event: 'onclick',  
                                    popup: true  
            }));            
 </script>  
                                                           Listing: 1

Replace the following attributes with your values :-

elementId : is the Id of the button /link which opens the pop up
formId : is the Id of the form where the pop up button belongs to

Sample Code from page:

 <form:form id="myform">  
 <input type="button" name="_eventId_review" id="popupbutton" value="Open Popup"  
  onclick="openPopupPage()" />  
 </form:form>  
 function openPopupPage() {  
    window.location.href = '${flowExecutionUrl}&_eventId=review';  
 }  
                                                             Listing: 2

Make sure to have org.springframework.js-2.0.3.RELEASE jar. This jar contains the Spring.js, Dojo.js ,Spring-Dojo.js  and the css referenced in the script tag

2. Modify Web.xml

In the above jsp code (Listing:1)you can see that we are referring to javascripts (dojo.js , Spring.js etc ) Those requests to the java scripts are handled by Resource Servlet in spring. So add the following servlet entry in web.xml to map the requests to java scripts to the resource servlet.

  <servlet>  
   <servlet-name>Resource Servlet</servlet-name>  
   <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>  
 </servlet>  
 <servlet-mapping>  
   <servlet-name>Resource Servlet</servlet-name>  
   <url-pattern>/resources/*</url-pattern>  
 </servlet-mapping>  
                                                               Listing: 3

3. Modify flowregistry.xml

Add popup="true" in the view-state of the popup page
 <view-state id="review" view="review" model="reviewModel" popup="true">  
 </view-state>  
Listing: 4

The pop up page is a normal jsp page. There is no special code to be put in the pop up page to open it as a pop up. The above steps I took from my working code.

Note: In IE8 and IE9 , it will not open as a pop-up , if we try to access the page using http://localhost:8080. You have to replace localhost with IP address or computer-name. This is because IE8 and IE9 handles localhost separately.

Hope this helps.

Friday, March 5, 2010

JSF reset form data when conversion fails

Problem:

My JSF form had some input text fields,one command link to another page, one command button for submit and one command button for reset. The text boxes accepts only Long values. I use a backing bean method in the action of reset button to reset the default values (pulled out from data base).

If character is entered in text box and a conversion error occured while sumbitting( save button) then if the user clicks reset or commandLink the same conversion error occurs. Because when we click reset or commandLink to another page, the page is going through the entire jsf life cycle where validtion and conversion happens before action. So we are getting the conversion error even if we try to reset the value.

We need the conversion error only when clicking save button and for reset , commandLink it should not throw any conversion error as these operations have nothing to do with the input data.

Solution:

Use immediate="true" with reset button and commandLink. With immediate attribute we are forcing the action to happen before conversion/validation occurs. Then the commandLink works fine as it is navigating to some other page. The reset button should show the same page with the default values set by the action method. This won't happen as expected. The submitted values will not be cleared even after reset. This is because the view is not getting rendered with immediate attribute. For this to happen we need to render the view explicitly in our code.

setting immediate attribute:


 <h:commandLink id="url_3" value="" immediate="true" action="#{BackingBean.approve}">Approve Page</h:commandLink>  
 <h:inputText size="4" value="#{BackingBean.productPrice}" converter="javax.faces.Long" converterMessage="Not a number"/>  
 <h:commandButton id="save" type="submit" value="Save" action="#{BackingBean.save}"/>  
 <h:commandButton id="reset" immediate="true" value="Reset" action="#{BackingBean.reset}"/>  
sample code to force the view in reset action method:
 public String reset(){  
   setInitialValues();  
   FacesContext context = FacesContext.getCurrentInstance();  
   Application application = context.getApplication();  
   ViewHandler viewHandler = application.getViewHandler();  
   UIViewRoot viewRoot = viewHandler.createView(context,context.getViewRoot().getViewId());  
   context.setViewRoot(viewRoot);  
   return "success" ;  
  }  
More information about immediate attribute:
Immediate attribute
More information about clearing input data:
Clear input component

JSF confirmation message based on action

Problem:

When user clicks a save button, the entered values are validated in a Backing bean method based on a business rule. If the validation fails, a confirmation message or pop up should be displayed to the user whether the user wishes to continue with save.

Solution:

This is little tricky. We call the validation method inside the action method of save button. We have to use a hidden parameter whose value is set to true if the validation fails ie we need to prompt the user. Using a javascript check if the value of hidden parameter is true then show the confirmation message. When user clicks ok in the confirmation message, from the javascript call the action (save) method of a hidden command button. Call the javascript on loading the page


Here is the javascript

 function showConfirmation(){  
  var value=document.getElementById('formId:valid').value;  
  if(value == "true"){  
   if(confirm("There are values that are at 0.Do you want to save the  information ?")){  
   document.getElementById('formId:hiddenButton').click();  
   }else{  
     return false  
    }  
  }  
 }  

jsf page:
 <body onload=showConfirmation()>  
  <h:form id="formId">  
  <h:commandButton id="save" type="submit" value="Save" action="#{BackingBean.save}"/>  
 <h:inputHidden id="valid" value="#{BackingBean.showconfirmation}"/>  
  <h:commandButton id="hiddenButton" value="hidden" action="#{BackingBean.saveWithZero}" style="visibility:hidden;" />  
 </h:form>  
 </body>  

Make sure that you set showconfirmation=false in your backing bean until you need to show the pop up.

Followers