How can I get geocoder address to backing bean? - jsf-2

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());
}

Related

Showing primefaces overlay panel leads to NPE in Mojarra code

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?

How to position a p:dialog in Prime Faces after its resizing

I have a Prime Faces p:dialog that has been resized while new components are inserted when opened ('show' state). However its position doesn't change and it's size is increasing from the down left corner until the page bottom.
I need to reposition it every time I render new components dynamically. Is there any JavaScript function I can call to its widget to reposition?
I'm using PrimeFaces 3.5 with Mojarra 2.1.13.
I had a similar situation with a TabView inside a dialog. The TabView content was dynamically loaded.
<p:dialog widgetVar="dialogWidgetVar">
<p:tabView value="#{tabBean.tabs}" var="tabsVar"
onTabShow="PF('dialogWidgetVar').initPosition();" dynamic="true">
<p:tab id="Tab#{tabsVar.id}" title="#{tabsVar.name}">
...
</p:tab>
</p:tabView>
</p:dialog>
As you can see it will call the function initPosition() with every change of a Tab. This function will reposition your dialog. You can use this function in several cases.
http://forum.primefaces.org/viewtopic.php?f=3&t=16893
This is a method that should work in your case :
Bean code :
#ManagedBean
#ViewScoped
public class Bean
{
private boolean visible;
public void setVisible(boolean visible)
{
this.visible = visible;
}
public boolean getVisible()
{
return this.visible;
}
public void onBeforeShowDialog(AjaxBehaviorEvent event)
{
visible = true;
}
public void onBeforeHideDialog(AjaxBehaviorEvent event)
{
visible = false;
}
}
View code :
<h:commandButton value="Show dialog">
<f:ajax listener="#{bean.onBeforeShowDialog}" render="dialog" />
</h:commandButton>
<p:dialog id="dialog" visible="#{bean.visible}">
content
<h:commandButton value="Hide dialog">
<f:ajax listener="#{bean.onBeforeHideDialog}" render="dialog" />
</h:commandButton>
</p:dialog>
A second method should also work is by JavaScript :
To add in <h:head /> :
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<script>
function centerAndShowDialog(dialog)
{
$(dialog).css("top",Math.max(0,(($(window).height() - $(dialog).outerHeight()) / 2) + $(window).scrollTop()) + "px");
$(dialog).css("left",Math.max(0, (($(window).width() - $(dialog).outerWidth()) / 2) + $(window).scrollLeft()) + "px");
dialog.show();
}
</script>
View code :
<p:commandButton id="basic" value="Show Dialog" onclick="centerAndShowDialog(dlg);" type="button" />
<p:dialog id="dialog" header="Dynamic Dialog" widgetVar="dlg" dynamic="true">
Content
</p:dialog>
Note : Since I'm not using PrimeFaces, I've not tested this code so I hope it work well, but the idea is here!

Conditional Submit through h:commandButton

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

JSF 2.0 with Richface 4.0 not rerendering component

Do you have any idea why this part of code isn't working:
View:
<a4j:commandButton value="#{labels.comments}"
action="#{reservation.displayComments}"
render="dataComments" />
<h:panelGroup id="dataComments" rendered="#{reservation.showComments}" >
...
<h:panelGroup/>
Bean:
public String displayComments(){
showComments = !showComments;
return "";
}
Click on the link simply do nothing.
Try something like this:
<a4j:commandButton value="#{labels.comments}"
action="#{reservation.displayComments}"
render="dataComments" />
<h:panelGroup id="dataComments">
<h:panelGroup id="innerPanel" rendered="#{reservation.showComments}" >
...
<h:panelGroup/>
<h:panelGroup/>
Always show your dataComments element, unless you will have nothing on the page to refresh.

IE Primefaces Enter Key Submit Workaround

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

Resources