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.

JSF confirmation message using javascript

Problem:

When a command button is clicked, display a prompt to the user if user selects 'OK' execute the action other wise stay in the current page.

Solution:

Use javascript confirmation dialog in <commandButton>


<h:commandButton value="Save" action="#{BackingBean.save}" onclick="if (!confirm('Are you sure you want to save?')) return false" >

If we return false from the javascript the action will not be executed.

JSF expanding row of data table

Problem :

To create a table from a list of objects obtained from DB in which each row has a button.On clicking the button the details of the row is displayed as next row.
This is not possible with JSF <h:dataTable>

Solution:

Use JSTL to iterate through the list and use plain html to create the table. 
Use jsf components inside the <td> of the table
Here is the sample code

 <table>  
 <tr class="colHdr">  
   <td >Column 1</td>  
   <td >Column 2</td>  
   <td >Column 3</td>  
   <td >Column 4</td>  
   <td >Column 5</td>  
 </tr>  
 <!-- use jstl1.2 for iterating the list of hardware objects-->  
 <c:forEach items="#{BackingBean.hardwareList}" var="hardware" varStatus="status">  
 <tr>  
   <td colspan="5" class="colStyle">  
     <h:outputText value="#{hardware.hardwareDesc}"/>  
   </td>  
 </tr>  
 <!--use status var to alter the row color -->  
 <tr class="${status.index % 2 == 0 ? 'style1' : 'style2'}">  
   <td> <!--use f:setPropertyActionListener to get which hardware's(row) detail button is clicked -->  
  <h:commandButton value="Hardware Details" action="#{BackingBean.details}">  
     f:setPropertyActionListener target="#{BackingBean.hardware}" value="#{hardware}" />  
  <!-- Backing bean must have getter and setter for hardware type -->  
  </h:commandButton>  
  </td>  
   <td><h:inputText size="4" value="#{hardware.col1}"/></td>  
   <td><h:inputText size="4" value="#{hardware.col2}"/></td>  
   <td><h:inputText size="4" value="#{hardware.col3}"/></td>  
   <td><h:inputText size="4" value="#{hardware.col4}"/></td>  
  <!-- this column is rendered only for hardware whose group is true-->  
   <td><h:inputText size="4" rendered="#{hardware.group}" value="#{hardware.col5}"/></td>  
 </tr>  
 <!-- On clicking the detail button set the showDetails   
 (of the corresponding hardware object obtained through the f:setPropertyActionListener)   
 to true in the backing bean -->  
 <h:panelGroup rendered="#{hardware.showDetails}">  
 <tr>  
 <td colspan="5">  
 <hr />  
 </td>  
 </tr>  
 <tr>  
   <td class="text1">Minimum</td>  
   <td class="text1"><h:outputText value="#{hardware.col1Min}"/></td>  
   <td class="text1"><h:outputText value="#{hardware.col2Min}"/></td>  
   <td class="text1"><h:outputText value="#{hardware.col3Min}"/></td>  
   <td class="text1"><h:outputText value="#{hardware.col4Min}"/></td>  
   <td class="text1"><h:outputText value="#{hardware.col5Min}"/></td>  
 </tr>  
 <tr>  
   <td class="genText">Optimal</td>  
   <td class="expLineAlt"><h:outputText value="#{hardware.col1Opt}"/></td>  
   <td class="expLineAlt"><h:outputText value="#{hardware.col2Opt}"/></td>  
   <td class="expLineAlt"><h:outputText value="#{hardware.col3Opt}"/></td>  
   <td class="expLineAlt"><h:outputText value="#{hardware.col4Opt}"/></td>  
   <td class="expLineAlt"><h:outputText value="#{hardware.col5Opt}"/></td>  
 </tr>  
 </h:panelGroup>  
 </c:forEach>  
 </table>  

Some useful links about customizing data table in JSF
expand-collapse-of-table-rows-in-datatable-jsf
Everything about data table in JSF

Tuesday, February 16, 2010

Jdeveloper 11g in Windows 7

I was trying to install Jdeveloper 11g in my windows 7 machine. I got it installed correctly, but the problem I had was when I started it then it was throwing some exception and it quited. The exception was something like the following:

oracle.adf.rc.config.ConfigurationException: an ADFContext has not been registered for name [oracle.jdeveloper.rescat2.ResourcePalette]. Root Cause=[] [Root exception is java.lang.NullPointerException]

In my case this issue was due to the user profile name in my system. It had spaces. The jdeveloper by default creates its directories in the C:\DocumentSetting\Users\
My profile name was like Vv & Aa. It had spaces before and after the ampersand. So what I did to make it work was to set the JDEV_USER_DIR to another folder.

In the command prompt set the JDEV_USER_DIR to some other folder of your choice.

set JDEV_USER_DIR = F:\myJdevProfile

Then go to the directory where jdeveloper is installed and start it from the command prompt

F:>jdeveloper> jdeveloper.exe

You have to start jdeveloper every time like this after setting the JDEV_USER_DIR
Other wise you can set it permenantly by setting the environment variable.

For windows 7, right click Computer, click properties, click Advanced system settings, click environment variables in the advanced tab. In the system variables, create new variable and give name as JDEV_USER_DIR and value as the directory of your choice. (here it is F:\myJdevProfile)

Here after you can start jdeveloper from the start menu itself by clicking the jdeveloper icon.

Some useful links:

http://forums.oracle.com/forums/thread.jspa?threadID=983953

http://jdeveloperfaq.blogspot.com/2009/12/faq-1-how-to-configue-stand-alone.html

Friday, January 22, 2010

Formating date in java

 Date date = new Date();  
 Format formatter = new SimpleDateFormat("MM/dd/yy");  
 String s= formatter.format(date);  
 System.out.println(s);  

Followers