JSF component is not rendered from my p:commandButton in in a dialog in included page - jsf

My page contains a login header that i include via ui:include. The included page contains a dialog with a p:commandButton. When the user logs in, the include page is refreshed properly according to the #form in the update attribute. I also want to update a component outside the included page, that shall display a button when the user is logged in. The include page refreshes and the name of the logged in user is displayed. But the button in the main page is not shown. It is displayed if I refresh the page though. I can't figure out what I'm doing wrong here. Anyone have any ideas.
The header page also displays the commandLink component properly. But when clicking the logout link, the button in the main page is not removed. Since the commandLink does not use ajax, I assume that a normal page POST is done. Which should reload the whole page. Doesn't this work from a page that have been referenced with ui:include?
The login page is using a session scoped backing bean. The main page is view scoped.
Here's the included xhtml (login.xhtml):
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<div style="width:100%;font-size:12px;line-height:20px;background-color:#b0d9e6;color:white">
<h:form>
<h:message id="top_msg"></h:message>
<h:panelGrid width="100%" columns="3" columnClasses="none,right1,right1">
<h:outputLink rendered="#{!loginController.loggedIn}" styleClass="text-align:right;" value="javascript:void(0)" onclick="PF('dlg').show();" title="login">
<p:outputLabel>Login</p:outputLabel>
</h:outputLink>
<h:commandLink rendered="#{loginController.loggedIn}" action="#{loginController.logout}" styleClass="text-align:right;" >
<h:outputLabel>Logout</h:outputLabel>
</h:commandLink>
<p:growl id="growl" sticky="true" showDetail="true" life="3000" />
<p:dialog header="Login" widgetVar="dlg" resizable="false">
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="username" value="Username:" />
<p:inputText id="username" value="#{loginController.username}" required="true" label="username" />
<h:outputLabel for="password" value="Password:" />
<p:password id="password" value="#{loginController.password}" required="true" label="password" />
<f:facet name="footer">
<p:commandButton value="Login"
update="#form :createform:createbutton"
actionListener="#{loginController.login}"
oncomplete="handleLoginRequest(xhr, status, args)" >
</p:commandButton>
</f:facet>
</h:panelGrid>
</p:dialog>
</h:panelGrid>
<script type="text/javascript">
function handleLoginRequest(xhr, status, args)
</script>
</h:form>
</div>
</ui:composition>
...
This one is included in the following main page:
...
<ui:include src="login.xhtml" />
<h:form id="createform">
<h:panelGroup id="createbutton" layout="block">
<p:commandButton id="createnew"
ajax="false"
action="#{recepieController.createNewRecipes}"
value="Create new recipe"
rendered="#{recepieController.loggedIn and !recepieController.create and !recepieController.viewOnly and !recepieController.edit}"
accesskey="s">
</p:commandButton>
</h:panelGroup>
</h:form>

You cannot rerender a non-rendered component. If you partially render a button, and the button is not rendered, you cannot call an update on that button, because it does not exist in the DOM.
You have to call the AJAX update on the parent naming container, that is ALWAYS rendered. Thus, update the :createform rather than the button inside. The form is always rendered, no matter what.

I found the issue. In my commandButton "createnew", I used the wrong value to render on.
<p:commandButton id="createnew"
ajax="false"
action="#{recepieController.createNewRecipes}"
value="Create new recipe"
rendered="#{recepieController.loggedIn and !recepieController.create and !recepieController.viewOnly and !recepieController.edit}"
accesskey="s">
</p:commandButton>
It should use my session scoped bean (loginController) to check if the user is logged in. Changing to the following works.
<h:panelGroup id="createbutton">
<p:commandButton id="createnew"
ajax="false"
action="#{recepieController.createNewRecipes}"
value="Create new recipe"
rendered="#{loginController.loggedIn and !recepieController.create and !recepieController.viewOnly and !recepieController.edit}"
accesskey="s">
</p:commandButton>
</h:panelGroup>
Note the difference rendered="#{loginController.login ...} instead of rendered="#{recepieController.loggedIn}"
The recepieController also has a loggedIn attribute which I set, but since the page is not re-posted I guess the value is not changed for the attribute when I login.
However, I believe I tested to use ajax="false" in the p:commandButton for the login dialog which I guess should reset the view scoped version of my loggedIn attribute. I don't fully understand why that didn't work.

Related

Primefaces p:messages dissappears after ajax call

My problem is that p:messages error message flashes and then dissappears. I understand that my ajax on h:commandButton clears the form but I need to keep the message inside the form and I cannot get my method to run in other ways I.E. p:commandButton onclick.
My xhtml code snippet from card.xhtml template:
<h:form id="cardForm">
<p:messages closable="true" id="msg">
<p:autoUpdate disabled="true"/>
</p:messages>
<h:commandButton
value="Add card to profile"
actionListener="#{cust.addCardToProfile('cards.xhtml')}"
rendered="#{not cart}">
<p:ajax oncomplete="addCardToProfile();" update=":cardForm:msg"/>
</h:commandButton>
<h:form>
How to correctly run my "addCardToProfile();" -method and update messages so it stays on the screen.
Original xhtml:
...
<p:remoteCommand name="addCard2OptionList"
actionListener="#{saml2IdPLoginController.addCard2OptionList}"/>
...
<p:outputPanel id="userCard">
<ui:define name="content">
<ui:include src="/WEB-INF/templates/card.xhtml"/>
</ui:define>
</p:outputPanel>
As suggested by #Melloware, It might have something to do with RemoteCommand component.

How to refresh the page after closing p:dialog

I've the below dialog:
<h:form id="r1">
<p:commandButton value="Basic" type="button" onclick="PF('dlg1').show();" />
<p:dialog header="Basic Dialog" widgetVar="dlg1">
<h:outputText id="test" value="Welcome to PrimeFaces" />
</p:dialog>
</h:form>
How can I refresh the JSF page after closing the dialog?
The <p:dialog> supports the ajax close event. This only requires it being placed inside a <h:form> (on contrary to the general recommendation), so you need to make sure that it's already manually poisitioned to the very end of the <h:body> and that you don't make use of appendToBody.
<h:body>
<h:panelGroup id="content" layout="block">
...
</h:panelGroup>
...
<h:form>
<p:dialog>
<p:ajax event="close" update=":content" />
...
</p:dialog>
</h:form>
</h:body>
Use if necessary update="#all" if you intend to update the entire page. But better is to update only the parts which really need to be updated.

How to target entire JSF page to be blocked by p:blockUI / pe:blockUI?

The example demonstrates blocking of <h:form> by <pe:blockUI>.
<h:form id="form" prependId="true">
<pe:blockUI target="form" widgetVar="blockBodyUIWidget">
<h:panelGrid columns="2">
<h:graphicImage library="default" name="images/ajax-loader1.gif" class="block-ui-image"/>
<h:outputText value="#{messages['blockui.panel.message']}" class="block-ui-text"/>
</h:panelGrid>
</pe:blockUI>
<p:commandButton id="btnSubmit"
onstart="PF('blockBodyUIWidget').block()"
oncomplete="PF('blockBodyUIWidget').unblock();}"
update=":form:dataGrid" actionListener="#{bean.listener}"
icon="ui-icon-check"
value="Save">
</h:form>
This blocks <h:form> but there is a template with a header and a left side bar which are not blocked by doing so.
I have tried to block <h:body id="body"> <pe:blockUI target="body"... on the template page but that didn't work ending with an exception indicating, "Cannot find component with the id body in the view."
So, how to target the entire page?
Although I'm using <pe:blockUI> of PrimeFaces extension, the same thing can be demonstrated by <p:blockUI> of PrimeFaces
Give an id to your body and then reference it on the block argument of the <p:blockUI> component.
Example:
<h:body id="entirePage"/>
and
<p:blockUI id="blockUI" widgetVar="blockBodyUIWidget" block=":entirePage"/>

p:commandbutton action doesn't work inside p:dialog

I have a p:dialog and there is a panel inside it. The problem is "Save" button's action method is not working. It doesn't even calls the method. I can reach the method def. with ctrl+lm so there is no problem with method name.
<h:body>
<h:form id="createAppUserForm" prependId="false">
....
<p:dialog id="newRoleDialogId"
header="Add New Role"
resizable="true"
draggable="true"
widgetVar="newRoleDetailsDialog"
appendToBody="true"
>
<p:panel id="newRoleDialogPanel">
<p:panelGrid id="newRoleDialogPanelGrid" columns="2" style="width: 100%" styleClass="panelGridWithoutBorder">
<h:outputText value="Role Name :"/>
<p:inputText value="#{createAppUserController.selectedRole.name}"/>
<h:outputText value="Role Desc :"/>
<p:inputText value="#{createAppUserController.selectedRole.description}"/>
</p:panelGrid>
<center>
<p:commandButton value="Save"
update="roleListDataTable newRoleDialogPanelGrid growlCreateAppUser"
oncomplete="if (!args.validationFailed) newRoleDetailsDialog.hide()"
action="#{createAppUserController.saveNewRole()}"/>
<p:commandButton value="Cancel"
immediate="true"
onclick="newRoleDetailsDialog.hide()" />
</center>
</p:panel>
</p:dialog>
</h:form>
</h:body>
The dialog, when used with an appendToBody/appendTo="#Body" must have its own form.
<p:dialog>
<h:form>
...
</h:form>
</p:dialog>
Because, when the dialog is generated into HTML output, it's by JavaScript relocated to the end of HTML <body> which causes it to not be sitting in any form anymore. The generated HTML DOM tree ends up to look like this (use webbrowser's dev tools to see it):
<body>
...
<form id="createAppUserForm">
...
</form>
...
<div id="newRoleDialogId" class="ui-dialog ...">
...
</div>
</body>
The appendToBody="true" plays a role in here. The end of body ensures easy and best cross browser compatibility of displaying a modal dialog by JavaScript.
The same is true by the way for a p:overlayPanel with an appendTo...
But also make sure there is, before 'moving' the p:dialog, there is not a nested h:form. So prevent
<h:form>
...
<p:dialog>
<h:form>
...
</h:form>
</p:dialog>
...
</h:form>
Since although it ends up like
<body>
...
<form id="createAppUserForm">
...
</form>
...
<div id="newRoleDialogId" class="ui-dialog ...">
<form>
...
</form>
</div>
</body>
it is initially invalid html
See also:
How to show details of current row from p:dataTable in a p:dialog and update after save
Creating master-detail table and dialog, how to reuse same dialog for create and edit
How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?
Adding (process="#this") to commandButton worked for me.
try this p:remoteCommand
http://www.primefaces.org/showcase/ui/ajax/remoteCommand.xhtml
this is my example
<h:commandButton value="Aceptar" type="button" onclick="irAConf()" class="art-button">
</h:commandButton>
<p:remoteCommand name="irAConf"
action="#{configuracionBean.irAConfiguracion}"/>
The appendToBody="true" plays a role in here. This attribute have been removed from in latest version. Please look for other alternative

p:resetInput does not reset the p:dialog when it is reopened

Here is some html I am writing to allow categories to be added using a dialog:
<p:dialog id="newCategoryDlg" header="Add New Category" widgetVar="newCategoryDialog" resizable="false">
<h:form id="newCategoryForm">
<p:panelGrid id="displayNewCategory" columns="2" cellpadding="4" style="margin:0 auto;">
<h:outputText value="Category Name :"></h:outputText>
<p:inputText value="#{categoryController.newCategory.name}"
required="true" requiredMessage="Please Enter a Category ID!" />
<f:facet name="footer">
<p:commandButton value="Submit" update=":form:categoryTable"
oncomplete="newCategoryDialog.hide();"
actionListener="#{categoryController.addCategory}">
<p:resetInput target="displayNewCategory" />
</p:commandButton>
<p:commandButton type="reset" value="Reset"></p:commandButton>
</f:facet>
</p:panelGrid>
</h:form>
</p:dialog>
Now, for whatever reason, "" just doesn't seem to work no matter which widget or identifier I use. All I want is for old input entries to disappear after they have been submitted. What am I doing wrong?
You misunderstood the purpose of <p:resetInput>. This misunderstanding is essentially already answered/explained here: Why does p:resetInput require properties of a managed bean to be set to null first after the form is submitted?
As to your concrete functional requirement of the need to update the dialog's content before opening, just do exactly that in the command button which opens the dialog:
<h:form>
<p:commandButton value="Open dialog" action="#{dialogBean.init}"
process="#this" update=":dialog" oncomplete="w_dialog.open()" />
</h:form>
...
<p:dialog id="dialog" widgetVar="w_dialog" ...>
Note that when the dialog contains fields which needs to be validated, then the <p:resetInput> would be very applicable in the button who's updating and opening the dialog in order to clear out invalid state.
See also:
How to show details of current row from p:dataTable in a p:dialog and update after save
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes

Resources