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

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!

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?

p:selectOneMenu changed when tab is changed

I have a Primefaces dialog, and inside it there is a tabView. In this tabView I have 3 tabs, each one called towards ui:include. In the first tab I have a selectOneMenu which defines a property called tipoProprietario from class ProprietarioORM. The navigation between tab is done not by tabs themselves (in this stage they're disabled) but towards commandButtons at bottom of dialog. When I click in a commandButton to pass from the first to second tab tipoProprietario is filled correctly. However, when I click to pass from second do third tab (or even to the first one), I found that the selectItem value is changed to null. Consequently, the tipoProprietario property is also changed to null. Debugging, I saw that first it is called the Select Item listener method and after the tipoProprietario setter.
Can someone explain why this it is happening? How to correct it?
dialog.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<p:dialog id="dlgEdicao" widgetVar="dlgEdicao" resizable="false"
closable="true" modal="true" closeOnEscape="true"
header="#{(proprietarioMB.edicao)? msg['proprietario.titulo.editar']: msg['proprietario.titulo.incluir']}">
<p:tabView id="tabEdicao" widgetVar="tabEdicao" dynamic="true"
styleClass="tabEdicaoProprietario" cache="false"
binding="#{proprietarioMB.tabEdicao}">
<p:tab id="tabProprietario" title="#{msg['proprietario.titulo']}"
disabled="#{not proprietarioMB.edicao}" titleStyleClass="">
<ui:include src="./aba_proprietario.xhtml" />
</p:tab>
<p:tab id="tabEnderecoContato"
title="#{msg['proprietario.titulo.aba.endereco']}"
disabled="#{not proprietarioMB.edicao}">
<ui:include src="./aba_endereco_contato.xhtml" />
</p:tab>
<p:tab id="tabVeiculo"
title="#{msg['proprietario.titulo.aba.veiculo']}"
disabled="#{not proprietarioMB.edicao}">
<ui:include src="./aba_veiculo.xhtml" />
</p:tab>
</p:tabView>
<f:facet name="footer">
<p:commandButton id="btnDialogoAnterior"
value="#{msg['titulo.anterior']}"
rendered="#{not proprietarioMB.edicao}" immediate="true"
disabled="#{not proprietarioMB.btnAnteriorHabilitado}"
actionListener="#{proprietarioMB.doEventClickBtnAnterior}"
update="#this tabEdicao btnDialogoSeguinte btnDialogoConcluir"
style="margin-right: 20px;" />
<p:commandButton id="btnDialogoSeguinte"
value="#{msg['titulo.proximo']} #{(not proprietarioMB.btnConcluirVisivel)? '': 'display: none;'}"
rendered="#{not proprietarioMB.edicao}"
actionListener="#{proprietarioMB.doEventClickBtnSeguinte}"
update="#this tabEdicao btnDialogoAnterior btnDialogoConcluir"
style="margin-right: 20px; #{(not proprietarioMB.btnConcluirVisivel)? '': 'display: none;'}" />
</f:facet>
</p:dialog>
</ui:composition>
aba_proprietario.xhtml (the first tab)
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<p:panel id="pnlDadosProprietario">
<p:focus for="selTipoEdicao" />
<p:fieldset id="fieldDadosProprietario"
legend="#{msg['proprietario.titulo']}"
rendered="#{not empty proprietarioMB.proprietario}">
<p:panelGrid id="pnlDadosProprietarioEdicao">
<p:row>
<p:column>
<p:outputLabel id="lblTipoEdicao"
value="#{msg['proprietario.titulo.tipo']}" for="selTipoEdicao" />
</p:column>
<p:column>
<p:selectOneMenu id="selTipoEdicao"
value="#{proprietarioMB.proprietario.tipoProprietario}"
valueChangeListener="#{proprietarioMB.doEventTipoDocumentoPesquisaChanged}"
immediate="true">
<f:selectItems value="#{proprietarioMB.tiposProprietarios}" />
<p:ajax event="change" update="txtDocumentoEdicao" />
</p:selectOneMenu>
</p:column>
<p:column>
<p:outputLabel id="lblDocumentoEdicao"
value="#{msg['proprietario.titulo.documento']}"
for="txtDocumentoEdicao" />
</p:column>
<p:column>
<p:inputMask id="txtDocumentoEdicao"
value="#{proprietarioMB.proprietario.documento}"
mask="#{proprietarioMB.mascaraDocumento}" />
</p:column>
</p:row>
</p:panelGrid>
</p:fieldset>
</p:panel>
</ui:composition>
The Managed Bean
#ManagedBean
#ViewScoped
public class ProprietarioMB {
private static final String MASCARA_CPF = "999.999.999-99";
private static final String MASCARA_CNPJ = "99.999.999/9999-99";
private static final SelectItem[] tiposProprietarios = new SelectItem[] {
new SelectItem(JURIDICA, JURIDICA.getDescricao()),
new SelectItem(FISICA, FISICA.getDescricao()), };
private ProprietarioORM proprietario;
private String mascaraDocumento;
private TabView tabEdicao;
/**
* Select Item listener method: Changes inputMask mask
*/
public void doEventTipoDocumentoPesquisaChanged(ValueChangeEvent event) {
this.mascaraDocumento = (event.getNewValue() == FISICA) ? MASCARA_CPF
: MASCARA_CNPJ;
}
public void doEventClickBtnAnterior() {
System.out.println("ProprietarioMB.doEventClickBtnAnterior(): "
+ this.tabEdicao.getActiveIndex());
this.tabEdicao.setActiveIndex(this.tabEdicao.getActiveIndex() - 1);
}
public void doEventClickBtnSeguinte() {
System.out.println("ProprietarioMB.doEventClickBtnSeguinte(): "
+ this.tabEdicao.getActiveIndex());
System.out.println("ProprietarioMB.doEventClickBtnSeguinte(): "
+ this.proprietario);
if (this.tabEdicao.getActiveIndex() == 0) {
if (this.validarProprietario()) { // Validation method
this.tabEdicao.setActiveIndex(1);
}
} else if (this.tabEdicao.getActiveIndex() == 1) {
this.tabEdicao.setActiveIndex(2);
}
}
// Other methods + getters & setters
}
ProprietarioORM
public class ProprietarioORM {
private String nome;
private TipoProprietarioEnum tipoProprietario;
// getters & setters
}
It's most likely because of the binding="#{proprietarioMB.tabEdicao}"
For one thing, you don't appear to need the binding at all. Even if you did, you failed to initialize the component in your backing bean, a bug that'll result in the <p:tabView/> attempting to bind to a null variable tabEdicao.
As you don't appear to be using the tabview variable in the backing bean, my recommendation would be to get rid of it. If you really need it, just initialize it:
private TabView tabEdicao = new TabView();
Kolossus:
This issue was resolved when I added the attibute dynamic="true" to dialog. Actually, the real value was dynamic=#{empty proprietarioMB.proprietario}, because I was geting NullPointerException when loading the page. proprietario property is loaded towards #PostConstruct method.

How can I get geocoder address to backing bean?

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

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