We are using JSF 2.0 in our project. Apart from Mojara, we are using Primefaces 3.3 forsome components.
we have a Requirement in our project that we HAVE to do Javascript validations (as part of client side validation) and then only the form submit should happen. The Validation done by JSF will anyway happen (at server side). But the Javascript validtions should also be there.
This was the reason I had asked this question but got no comments.
I am therefore implementing the JavaScript validations and this brings me to the actual problem i am facing.
I have JS functions to do basic validations like "Required" fields, length check etc and calling them at appropiate time (like onblur). But if the user just leaves all the fields empty or does not go into some fields at all(thereby not triggering events like onblur) and clicks on the submit button, these fields are missed out for JS validations.
So how do i conditionally submit the form after all the JS validaitions are done?
Note that we have to use f:ajax for form submit.
I tried the onsubmit function of the form. It works on FF but not on IE9.
I tried the onclick function of the commandbutton. It calls the js but submits the form also.
Few code if that helps
JavaScript functions I am using
var validationErrorFound = false;
function validateRequired(element,form){
if(null == element.value || "" == element.value){
var existingClass = element.getAttribute("class");
var newClass = existingClass + " inputError";
element.setAttribute("class", newClass);
var label = document.getElementById(element.getAttribute("id") + "Lbl");
var labelArray = new Array();
var temp = label.innerText;
labelArray = temp.split(":");
element.setAttribute("title", labelArray[0] + " is Required");
validationErrorFound = true;
}else{
element.className = element.className.replace( /(?:^|\s)inputError(?!\S)/ , '' );
element.setAttribute("title", null);
element.removeAttribute("title");
validationErrorFound = false;
}
}
function validateAllRequired(form){
var all = document.getElementsByTagName("input");
var max=all.length;
for (var i=0; i < max; i++) {
if(null != all[i].onblur ){
validateRequired(all[i],form);
}
}
return validationErrorFound;
}
JSF Page
<h:form id="addUserDetailsForm">
<h:messages/>
<h:panelGrid columns="2">
<p:outputLabel id="userNameLbl" for="userName" value="Username:" />
<p:inputText id="userName" required="true" onblur="validateRequired(this,this.form);"
value="#{userList.addUser.userName}">
<f:param name="req" value="true"/>
</p:inputText>
<p:outputPanel value="" />
<p:outputLabel id="firstNameLbl" for="firstName" value="First Name:" />
<p:inputText id="firstName" required="true" onblur="validateRequired(this,this.form);"
value="#{userList.addUser.firstName}"/>
<p:outputLabel id="lastNameLbl" for="lastName" value="Last Name:" />
<p:inputText id="lastName" required="true" onblur="validateRequired(this,this.form);"
value="#{userList.addUser.lastName}"/>
<h:commandButton styleClass="button" value="Add" onclick="validateAllRequired(this.form);"
action="#{userList.dummyAdd}" >
<f:ajax execute="#form" render=":mainArea :propertiesArea" update=":mainArea :propertiesArea"/>
</h:commandButton>
</h:panelGrid>
Is there any way this can be done?
Thanks
Related
I have a data table displying some application parameters having 3 columns:
name (outputext),
value (p:cellEditor) and
edit (p:rowEditor used)
On clicking edit button in any row value field converts into input field and is having validator attached. After changing and accepting( clicking check icon) values an 'update button' is provided at the bottom of page to save all changes.
My problem is if a validation error comes and we press 'update button' then call goes to save function in managed bean with old value. So to stop this I want to disable 'update button' when any row is having edit mode opened. Can I check the mode of all cell editors in column 2 , so I will use that in disabled attribute of update button.
Please do suggest any other better way is also possible ?
Using a jsf 2.1 and primefaces 3.5
XHTML snippet
<!-- Body panel for display of individual configuration mode -->
<p:panel id="mainConfigPanel" >
<!-- status message section -->
<p:messages id="msg" autoUpdate="true" closable="true"/>
<!-- Parameter configuration mode -->
<p:panel
rendered="#{configMBean.configUtility.configParamModeOn}"
styleClass="panelNoBorder">
<p:dataTable id="configParamTable" var="configParamVar"
value="#{configMBean.configParamList}" editable="true">
<p:ajax event="rowEdit" listener="#{configMBean.onRowEdit}" update=":mainForm:msg" />
<p:ajax event="rowEditCancel" listener="#{configMBean.onRowCancel}" update=":mainForm:msg" />
<p:column headerText="Parameter Name" sortBy="#{configParamVar.paramConfigName}">
<h:outputText id="paramNameId" value="#{configParamVar.paramConfigName}" />
</p:column>
<p:column headerText="Param Value" sortBy="#{configParamVar.paramConfigValue}">
<p:cellEditor>
<f:facet name="output" > <h:outputText value="#{configParamVar.paramConfigValue}" /> </f:facet>
<f:facet name="input">
<p:inputText id="paramValueId" value="#{configParamVar.paramConfigValue}" required="true"
validator="#{configMBean.validateParam}" >
<f:validateLength maximum="2000" />
<f:attribute name="input" value="#{configParamVar}" />
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Edit" style="text-align:center;vertical-align:top;width:20px">
<p:rowEditor />
</p:column>
</p:dataTable>
<h:panelGrid columns="2" >
<p:commandButton value="Update Parameters" actionListener="#{configMBean.saveParamUpdate}" update=":mainForm" />
<p:commandButton value="Cancel" actionListener="#{configMBean.cancelParamUpdate}" immediate="true" update=":mainForm">
</p:commandButton>
</h:panelGrid>
</p:panel>
<!-- End of Parameter configuration mode panel -->
</p:panel>
<!-- End of body panel for individual configuration mode -->
</p:panelGrid>
<!-- end of main panel -->
Functions in Managed Bean
public void onRowEdit(RowEditEvent event) {
System.out.println(" In Row Edit");
}
public void onRowCancel(RowEditEvent event) {
System.out.println("In Row Canel of Parameter Config");
}
public void validateParam(FacesContext facesContext, UIComponent component,
Object value) throws ValidatorException, Exception {
if (value != null) {
//Getting parameter Name and Value for validation
String paramName = ((RowEntity) component.getAttributes().get("input")).getParamConfigName();
String paramValue = (String) value;
FacesMessage msg = null;
//Validation Cases
if (paramName.equalsIgnoreCase(ResourceBundle.getMsg("Param_Enable_FTP"))) {
if (!paramValue.equalsIgnoreCase("true") || !paramValue.equalsIgnoreCase("false")) {
msg = new FacesMessage(FacesMessage.SEVERITY_WARN, ResourceBundle.getMsg("Param_True_False_Validation")+ paramName, "");
throw new ValidatorException(msg);
}
} else if (paramName.equalsIgnoreCase(ResourceBundle.getMsg("Param_Contingency_Reserve"))) {
if (!Pattern.matches("-?\\d*\\.?\\d*", paramValue)) {
msg = new FacesMessage(FacesMessage.SEVERITY_WARN, ResourceBundle.getMsg("Param_Number_Validation") + paramName, "");
throw new ValidatorException(msg);
}
}// end if else if
}
}
From the docs: There is an Ajax Behavior Event for rowEdit
rowEdit | org.primefaces.event.RowEditEvent | When a row is edited.
You could disable the update button when the RowEditEvent got fired and release the button after the row editing was canceled or saved.
I Hope I got your question right and this helps.
I use a p:overlayPanel on several places. It offers values from which the user can choose. This overlay panel is parameterized and used on several places. Therefore I show the panel with a click on a button like this:
<p:commandButton oncomplete="PF('overlayPanelVar').loadContents('#{component.clientId}');" immediate="true" actionListener="#{myController.setSelectedObject(curMaskElement, curDummyCssClass)}" process="#this" />
This works but only in one case I get a NullPointerException in JSF implementation mojarra this commandButton was created inside ui:repeat.
When the user clicks on the button it works and overlay panel appears, but if a value is chosen from the overlay panel (which is a link) this happens:
15:16:30,873 SEVERE [org.primefaces.application.exceptionhandler.PrimeExceptionHandler] (http-/0.0.0.0:9090-5) null: java.lang.NullPointerException
at com.sun.faces.facelets.component.UIRepeat.restoreChildState(UIRepeat.java:433) [jsf-impl-2.2.12.jar:2.2.12]
at com.sun.faces.facelets.component.UIRepeat.restoreChildState(UIRepeat.java:448) [jsf-impl-2.2.12.jar:2.2.12]
at com.sun.faces.facelets.component.UIRepeat.restoreChildState(UIRepeat.java:415) [jsf-impl-2.2.12.jar:2.2.12]
at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:546) [jsf-impl-2.2.12.jar:2.2.12]
at com.sun.faces.facelets.component.UIRepeat.invokeOnComponent(UIRepeat.java:695) [jsf-impl-2.2.12.jar:2.2.12]
at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1503) [jsf-api-2.2.12.jar:2.2]
at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:714) [jsf-api-2.2.12.jar:2.2]
at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1503) [jsf-api-2.2.12.jar:2.2]
at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:714) [jsf-api-2.2.12.jar:2.2]
at com.sun.faces.facelets.component.UIRepeat.invokeOnComponent(UIRepeat.java:697) [jsf-impl-2.2.12.jar:2.2.12]
The code in mojarra UIReapeat.class:
private void restoreChildState(FacesContext faces, UIComponent c) {
// reset id
String id = c.getId();
c.setId(id);
// hack
if (c instanceof EditableValueHolder) {
EditableValueHolder evh = (EditableValueHolder) c;
String clientId = c.getClientId(faces);
SavedState ss = this.getChildState().get(clientId);
if (ss != null) {
ss.apply(evh);
} else {
String childId = clientId.substring(initialClientId.length() + 1);
childId = childId.substring(childId.indexOf(getSeparatorChar(faces)) + 1);
childId = initialClientId + getSeparatorChar(faces) + childId;
if (initialChildState.containsKey(childId)) {
SavedState initialState = initialChildState.get(childId);
initialState.apply(evh);
} else {
NullState.apply(evh);
}
}
}
// continue hack
Iterator itr = c.getFacetsAndChildren();
while (itr.hasNext()) {
restoreChildState(faces, (UIComponent) itr.next());
}
}
The initialClientId member is null.
This appears with version 2.2.12.
If I change the JSF implementation of JBoss 6.2 to bundled which comes with JBoss this exception does not occur. The jars are jboss-jsf-api_2.1_spec-2.1.19.1.Final-redhat-1.jar and jsf-impl-2.1.19-redhat-2.jar.
In another usage of the overlay panel I create the commandButton inside a h:dataTable iteration and it works.
This is probably a mojarra bug?
The NPE occurs when the commandButton is created like this:
<p:panelGrid styleClass="searchMaskFieldsGrid">
<ui:repeat value="#{curSearch.getSearchMaskDescription().getRows()}" var="curRow" varStatus="rowStatus">
<p:row styleClass="searchMaskRow">
<ui:repeat value="#{curRow.elements}" var="curMaskElement" varStatus="colStatus">
<p:column colspan="#{curMaskElement.columnSpan}"
styleClass="#{curMaskElement.isLabel() ? 'searchMaskLabelColumn' : 'searchMaskInputColumn'}">
<!-- this includes one field and here can be the commandButton be added -->
<ui:include src="/sections/search/searchFields.xhtml">
<ui:param name="curMaskElement" value="#{curMaskElement}" />
<ui:param name="curRowIndex" value="#{rowStatus.index}" />
<ui:param name="curColumnIndex" value="#{colStatus.index}" />
</ui:include>
</p:column>
</ui:repeat>
<ui:param name="unfilledColumnsCount" value="#{searchBL.determinedUnfilledColumns(curSearch.getSearchMaskDescription(), curRow)}" />
<p:column colspan="#{unfilledColumnsCount}" rendered="#{unfilledColumnsCount gt 0}">
<h:outputLabel value="" />
</p:column>
</p:row>
</ui:repeat>
</p:panelGrid>
Is it maybe a known limitation with PF('overlayPanelVar').loadContents('#{component.clientId}'); and ui:repeat and someone knows a workaround?
Is it possible to update view parameter without redirecting the page? For instance
I have a managed bean which checks if an ID exist
public void signIn(){
Client c = clientFacade.loginDetail(client.getID());
if (c != null) {
loggedIn = true;
}
else{
loggedIn = false;
}
}
and a view which renders just fine if the ID exist.
<h:panelGroup rendered="#{not applicationManager.loggedIn}">
<p:commandLink value="Sign In" onclick="loginDialog.show()" styleClass="login-link"></p:commandLink>
</h:panelGroup>
<h:panelGroup rendered="#{applicationManager.loggedIn}">
<p:menuButton value="#{applicationManager.client.firstname}" />
</h:panelGroup>
<p:dialog widgetVar="loginDialog" >
<h:panelGrid columns="2" cellpadding="5">
ID : <p:inputText value="#{applicationManager.client.id}" />
<p:commandButton value="submit" action="#{applicationManager.signIn()}" update=":loginForm" />
</h:panelGrid>
</p:dialog>
Is it possible to insert the code below at the top of the view and still have an update on the url?
<f:metadata>
<f:viewParam name="input" value="#{applicationManager.client.id}" />
<f:event listener="#{applicationManager.signIn()}" type="preRenderView"/>
</f:metadata>
I tried it, but it's not working, so I guess I might be missing something or doing something wrong.
Using PrimeFaces p:gmap component.
I have a page with a gmap component with a set of markers.
I want to display the street address in the gmapInfoWindow and pass it to the backing bean as well.
When I click on the map marker, I call a javascript function to get the reverse geocoder address.
I can fetch the address and display it in a javascript alert dialog, but I can't get it to fill the backing bean variable or in the info marker.
The variable does get filled, but it does not get updated until the next time I click on the marker.
As a result, the addresses are always one marker click behind.
Does anyone know how I can get the address to update during the current page session?
Thanks.
The backing bean code onMapMarkerSelect just has a System.out.println statement to show the mapAddress variable.
Here is the page code:
<h:form prependId="false" >
<p:gmap id="gmap" center="#{mappingSessionBean.mapCenter}" zoom="#{mappingSessionBean.mapZoom}" type="HYBRID" rendered="true"
style="#{mappingSessionBean.polygonGmapStyle}" onPointClick="handlePointClick(event);"
model="#{mappingSessionBean.mapModel}" fitBounds="#{mappingSessionBean.fitBoundsFlag}"
widgetVar="map" >
<p:ajax id="gmapAjax" event="overlaySelect" immediate="true" onstart="handlePointClick(event);" listener="#{mappingSessionBean.onMapMarkerSelect}" />
<p:gmapInfoWindow id="infoWindow" >
<p:outputPanel >
<h:panelGrid columns="1" >
<h:outputText id="infoWindowTitle" value="#{mappingSessionBean.selectedMarker.title}" />
<h:outputText id="infoWindowAddress" value="#{mappingSessionBean.mapAddress}" rendered="true" />
<p:commandButton value="Zoom In" action="#{mappingSessionBean.selectedViewInfoListener}" update="gmap" />
</h:panelGrid>
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
<h:inputHidden id="address" value="#{mappingSessionBean.mapAddress}" />
</h:form >
<script type="text/javascript" >
function handlePointClick(event) {
if(navigator.geolocation)
{
browserSupportFlag = true;
var latlng = event.latLng;
geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': latlng}, function(results, status)
{
if( status == google.maps.GeocoderStatus.OK )
{
alert( results[0].formatted_address );
document.getElementById('address').value = results[0].formatted_address;
document.getElementById('infoWindowAddress').value = results[0].formatted_address;
}
else
{
alert( "Geocoder failed due to: " + status );
}
});
}
else
{
alert( "No Geolocation");
}
}
</script>
Here is a general solution, I guess you can do better if you will find a way to trigger an event on inputHidden without the use of the button
b.t.w : jQuery comes with primefaces so you can use it without any additional includes
instead of
<h:inputHidden id="address" value="#{mappingSessionBean.mapAddress}" />
place
<f:ajax listener="#{mappingSessionBean.myajax}" execute="address">
<h:inputHidden id="address" value="#{mappingSessionBean.mapAddress}" />
<h:commandButton id="addressBtn" style="display:none"/>
</f:ajax>
(you can replace execute="address" with execute="#form")
and in js code replace
document.getElementById('address').value = results[0].formatted_address;
with
jQuery("#address").val(results[0].formatted_address);
jQuery("#addressBtn").click(); // this will trigger the ajax listener
and finally in your bean add the implementation of the ajax listener itself
public void myajax(AjaxBehaviorEvent event) {
System.out.println(getMapAddress());
}
I've run into and issue with IE not allowing me to hit the enter key to submit a form. I found a partial solution (http://www.thefutureoftheweb.com/blog/submit-a-form-in-ie-with-enter) but my dialog window closes. My validations are run and the error messages are displayed. How would I keep my dialog open?
<p:dialog id="sgupdlg" header="#{bundle['signUp.HEADER']}" widgetVar="signUpDlg"
modal="true" styleClass="dialog dialog1" draggable="false"
resizable="false" showEffect="fade" hideEffect="fade" position="top">
<h:form id="signUpFrm" binding="#{signUpDetail.signUpFrm}">
<p:growl id="growl" showDetail="true" showSummary="false" life="3000" errorIcon="/images/Validation-Error.png" infoIcon="/images/Validation-Success.png"/>
<p:inputText value="#{signUpDetailBean.firstName}" name="nameInput" required="true" requiredMessage="First Name is Required"/>
<p:inputText value="#{signUpDetailBean.lastName}" required="true" requiredMessage="Last Name is Required"/>
<p:commandButton styleClass="form-btn2"
value="#{bundle['signUp.button.LABEL']}" actionListener="#{signUpDetail.signUp}" onclick="trackingSignUpOverlaySave()"
oncomplete="handleSignUpRequest(xhr, status, args)" update="growl"/>
<p:commandButton type="reset" styleClass="close" />
</h:form>
</p:dialog>
<script type="text/javascript">
$ = jQuery
$(function(){
$('input').keydown(function(e){
if (e.keyCode == 13) {
$('#signUpFrm').submit();
return false;
}
});
});
</script>
function closeWhenValidationSuccesful(dialog, xhr, status, args) {
if (!args.validationFailed) {
dialog.hide();
}
}
<p:commandButton value="Save" action="doSomething" update=":formName:panelContainingValidatedElements"
oncomplete="closeWhenValidationSuccesful(dialogWidgetVar, xhr, status, args)" />
I use the following to keep a dialog open and display validation errors. You will need to move your inputs into a panelGrid so that it can be target by the update attribute.
A simple tag would solve it.
oncomplete="if (args.validationFailed){} else {Professor.show(),Student.hide();}"
you suppose to apply this on Professor widget var