PrimeFaces Panel collapses on update - jsf

I do not know if this is possible using just primefaces and JSF but I have a panel, which is collapsed on View Entry. I can open the Panel which has a checkbox that triggers an update of the Panel.
The problem is that when the panel is updated by Ajax, the Panel is collapsed again. But I want to retain the current open status of the Panel. It should no close on update. Is this possible?
I use PF 3.2 and JSF2.1
<p:fieldset style="width:200px;height:300px;overflow:auto;">
<h:outputLabel value="Available Applications"
style="font-weight: bold;font-size: 14px;" />
<br />
<br />
<h:panelGroup>
<ui:repeat var="category"
value="#{epsEditController.subscriptionCategoryVOs}">
<p:panel header="#{category.applicationCategory.name}"
id="panell" toggleable="true" closable="false" toggleSpeed="500"
collapsed="true"
widgetVar="panel_#{category.applicationCategory.name}">
<h:panelGrid columns="2" border="0">
<h:outputLabel value="Select all"
style="font-weight: bold;float:left;" />
<p:selectBooleanCheckbox value="#{category.allSelected}">
<p:ajax event="change"
listener="#{epsEditController.selectionChanged(category)}"
update="panell" />
</p:selectBooleanCheckbox>
</h:panelGrid>
<ui:repeat var="subcat"
value="#{category.applicationSubcategoryVOs}">
<p:selectBooleanCheckbox value="#{subcat.selected}"
title="#{subcat.applicationSubcategory.name}"
itemLabel="#{subcat.applicationSubcategory.name}" />
</ui:repeat>
</p:panel>
</ui:repeat>
</h:panelGroup>
</p:fieldset>

The reason the panel was collapsed after each update is caused by using a static collapsed="true" on the panel. This can be fixed in one of two ways
Just updating the content of the panel and not the panel
Keeping track of the state of collapsed state of the panel via ajax and use that state as the value of the collapsedattribute
Updating the content
By putting the form within the panel and only updating that form you effectively update the content instead of the panel. This makes sure that only the form is refreshed and the panel state is kept intact.
<p:panel header="#{category.applicationCategory.name}" id="panell"
toggleable="true" closable="false" toggleSpeed="500"
collapsed="true"
widgetVar="panel_#{category.applicationCategory.name}">
<h:form id="epsAppForm">
<h:panelGrid columns="2" border="0">
<h:outputLabel value="Select all"
style="font-weight: bold;float:left;" />
<p:selectBooleanCheckbox value="#{category.allSelected}">
<p:ajax event="change"
listener="#{epsEditController.selectionChanged(category)}"
update="#form" />
</p:selectBooleanCheckbox>
</h:panelGrid>
........
</h:form>
</p:panel>
Using EL instead of a fixed value
You can put EL in the collapsed attribute instead of the fixed collapsed="true". Something like
collapsed="#{myBean.toggleStates[category.applicationCategory]}"
You can then keep track of the state of the pannel via ajax calls
<p:ajax event="toggle" listener="#{myBean.toggleState(category.applicationCategory)" />
...'myBean' code:
Map<ApplicationCategory, boolean> toggleStates = new HashMap<>();
... prepopulate toggleStates on #init or something
public void toggleState(ApplicationCategory myCategory) {
toggleStates.put(myCategory, !(toggleStates.get(myCategory));
}

Related

p:dataGrid content disappears after ajax update

I got a little problem with p:ajax update here. After closing p:panel or checking checkbox or adding answer i'm ajax-updating ans-data-grid as you can see in the code. But it works only for add answer button. When i close panel or click checkbox content of p:datagrid dissapears. It's still there but it is not visible and whole datagrid is 0px high. So my question is, Is there a difference between update from p:commandButton and p:ajax, and if yes how can i update this datagrid properly?
<p:panel id="edit_ans_panel" styleClass="edit-ans-panel" visible="#{editorBean.question.qtype != 2}">
<p:dataGrid rowIndexVar="rowIndex" var="answer" value="#{editorBean.question.answers}" columns="1" id="ans_data_grid">
<p:panel header="Answer" styleClass="QApanel" closable="#{editorBean.closableAns}" toggleable="true">
<p:ajax event="close" update="ans_data_grid" listener="#{editorBean.onAnswerRemoved(answer)}" />
<p:panelGrid columnClasses="anscol1,anscol2,anscol3" columns="3" layout="grid" styleClass="QAgrid">
<p:inputTextarea placeholder="enclose LaTeX expression in $ to be processed" id="editor_input_#{answer.id_answer}" styleClass="editor-input" minQueryLength="2" value="#{answer.text}" />
<h:outputText id="editor_output_#{answer.id_answer}" styleClass="editor-output" value="#{answer.text}"/>
<p:column>
<p:panel id="edit_ans_corr_chkbx" styleClass="edit-ans-corr-chkbx" visible="#{editorBean.question.qtype != 3}">
<h:outputText value="Correct: " />
<p:selectBooleanCheckbox id="is_true_#{answer.id_answer}" value="#{answer.is_true}" >
<p:ajax update="ans_data_grid" listener="#{editorBean.ansChecked(answer)}" />
</p:selectBooleanCheckbox>
</p:panel>
</p:column>
</p:panelGrid>
</p:panel>
</p:dataGrid>
<p:commandButton id="add_ans_btn" value="Add Answer" styleClass="add-ans-btn" action="#{editorBean.addAnswer()}" update="ans_data_grid"/>
</p:panel>
\edit
For some reason p:panel with .QApanel class gets .ui-helper-hidden class after update where is display:none.

How to update panel by doing action from panel grid in jsf

Trying to update panel by clicking button from another panelgrid.but not working
<h:panelGrid columns="3" id="qualaddpanelgrid12">
<p:selectOneMenu value="#{qualCntrl.qualificationGroup}" id="qualificationGroup" style="width:180px;" disabled="#{qualCntrl.dropDownEnable}">
<f:selectItem itemLabel="Please Select" Value="P" />
<f:selectItems itemLabel="#{qualCntrl.qualificationGroupList()}" value="#{qualCntrl.qualificationGroupList()}" />
</p:selectOneMenu>
<p:commandButton icon="ui-icon-plus" actionListener="#{qualCntrl.enableGroupPanel}" update="qualaddpanelgrid12,groupPanel" ></p:commandButton>
<p:panel id="groupPanel" header="Add New Group" closable="true" widgetVar="groupPanel" style="width:170px;" rendered="#{qualCntrl.groupPanelEnable}">
</p:panel>
groupPanel is not updating.
I guess you problem is that your panel wont appear on the screen.
The cause of this is that you can't update a component which is not rendered. You have to put your p:panel into another p:panel (or any container component) and update the outer component.
e.g.:
<p:commandButton icon="ui-icon-plus" actionListener="#{qualCntrl.enableGroupPanel}" update="qualaddpanelgrid12,updateMe" />
<p:panel id="updateMe">
<p:panel id="groupPanel" header="Add New Group" closable="true" widgetVar="groupPanel" style="width:170px;" rendered="#{qualCntrl.groupPanelEnable}"></p:panel>
</p:panel>

Primefaces Dialog not working with Chrome

I have a p:dialog. My intention is to create a list using p:datagrid and when user clicks an item this dialog will open and show its details. Please consider the example of p:datagrid in the showcase. However, currently it works fine in IE but not in Chrome. If I define "modal=true" then the browser turns black but the dialog doesn't show up.
<p:commandButton update=":form:sharePanel" value="Share" style="font-size: 10px" oncomplete="PF('dlg').show()" rendered="false">
<f:setPropertyActionListener target="#{shareController.current}" value="#{status}" />
</p:commandButton>
<p:dialog widgetVar="dlg" resizable="false" id="sharePanel" styleClass="no-border" modal="true">
<h:outputText value="#{shareController.current.url.url}" />
<h:panelGrid columns="3">
<p:dataGrid value="#{shareController.current.url.NLinkList}" var="nshare" columns="1" rendered="#{shareController.current.url.NLinkList.size() > 0}">
<h:panelGroup styleClass="tag noun">
<h:outputText value="#{nshare.noun}" />
</h:panelGroup>
</p:dataGrid>
<p:dataGrid value="#{shareController.current.url.VLinkList}" var="vshare" columns="1" rendered="#{shareController.current.url.VLinkList.size() > 0}">
<h:panelGroup styleClass="tag verb">
<h:outputText value="#{vshare.verb}" />
</h:panelGroup>
</p:dataGrid>
<p:dataGrid value="#{shareController.current.url.PLinkList}" var="pshare" columns="1" rendered="#{shareController.current.url.PLinkList.size() > 0}">
<h:panelGroup styleClass="tag prep">
<h:outputText value="#{pshare.prep}" />
</h:panelGroup>
</p:dataGrid>
</h:panelGrid>
</p:dialog>
What is wrong here?
If you are using Primefaces versions before 4.0 use dlg.show() instead of PF('dlg').show().
And try appending the dialog in body using attribute appendToBody="true", because if the Facelet is more complex and if you are using Layouts the dialog won't fire ind some browsers only model will appear.
<p:dialog appendToBody="true" >

JSF PrimeFaces overlayPanel submit value

I would like to submit value form jsf page to bean from overlayPanel with checkbox like this:
To show overlay panel and ajax submission I use this code, and see it's OK in debugger:
<p:commandButton id="joinBtn" value="Basic" type="button" disabled="#{dataPropertyCurrent.notJoinable}"/>
<p:overlayPanel id="joinPanel" for="joinBtn" appendToBody="true" dynamic="false">
<f:facet name="header">Details</f:facet>
<p:dataList value="#{treeBean.getDataPropsCouldBeJoinedWith(dataPropertyCurrent)}" type="definition" var="dataJoinVal">
<h:panelGrid columns="2" cellpadding="10">
<h:column>
<p:selectBooleanCheckbox value="#{dataJoinVal.checked}" id="cbID">
<p:ajax event="change" update="cbID" partialSubmit="true"/>
</p:selectBooleanCheckbox>
</h:column>
<h:column>
<h:outputText value="#{dataJoinVal.caption}" />
</h:column>
</h:panelGrid>
</p:dataList>
<!--<p:commandButton value="Apply" id="btnApplyJoin" type="button" process="#parent" />-->
<h:outputLabel value="ID: #{dataPropertyCurrent.joinDataPropertyId}" />
</p:overlayPanel>
But after it when the overlayPanel is hidden and form submit button being pressed with this code:
<p:commandButton value="Apply join" update="joinAccordionPanel,dsAccordionPanelMain" actionListener="#{treeBean.applyJoinOptions}" />
it sets "false" to bean boolean value again.
So how to submit overlayPanel value to bean properly?
PrimeFaces version: 3.5
I've found explanation here: http://forum.primefaces.org/viewtopic.php?f=3&t=30550#p97737:
"If you are using appendToBody, it's strongly recommended to have a form inside the overlayPanel component that wraps all of the input fields and buttons. This is what you have done in your last solution. However, this means that you cannot place the overlayPanel inside another form in the xhtml page because of the limitation on nesting forms. The best solution is typically to avoid appendToBody wherever it's not absolutely necessary."
Edit
I've added <h:form> inside overlayPanel, and now it works fine:
<p:overlayPanel id="joinPanel" for="joinBtn" appendToBody="true" dynamic="true" >
<h:form id="formTmp">
<f:facet name="header">Details</f:facet>
<p:dataList value="#{treeBean.getDataPropsCouldBeJoinedWith(dataPropertyCurrent)}" type="definition" var="dataJoinVal">
<h:panelGrid columns="2" cellpadding="10">
<h:column>
<p:selectBooleanCheckbox value="#{dataJoinVal.checked}" id="cbID">
<p:ajax event="change" update="cbID" partialSubmit="true"/>
</p:selectBooleanCheckbox>
</h:column>
<h:column>
<h:outputText value="#{dataJoinVal.caption}" />
</h:column>
</h:panelGrid>
</p:dataList>
</h:form>
</p:overlayPanel>

How to update component on clientside in primefaces?

I want to create add children button with dialog form feature.
On the page there are tree and modal dialog form. On every node of tree will be the create child button. If you click on create child button, there will be shown modal form, where parentId will be set as id of node where button was clicked
Tree:
<h:form id="TestGroupListForm">
<p:tree value="#{testTreeController.root}" var="node" dynamic="true" cache="false"
selectionMode="single" selection="#{treeBean.selectedNode}" id="tree">
<p:treeNode>
<h:outputText value="#{node.getName()}" /> <p:commandButton id="createButton#{node.getIdTestGroup()}" icon="ui-icon-plus" value="#{bundle.Create}" update="tree" oncomplete="TestGroupCreateDialog.show()"/>
</p:treeNode>
</p:tree>
</h:form>
Dialog Box:
<h:form id="TestGroupCreateForm">
<h:panelGroup id="display">
<p:panelGrid columns="2" >
<p:outputLabel value="#{bundle.CreateTestGroupLabel_name}" for="name" />
<p:inputText id="name" value="#{testGroupController.selected.name}" title="#{bundle.CreateTestGroupTitle_name}" />
<h:inputHidden id="parentId" value="#{testGroupController.selected.parentId}" />
</p:panelGrid>
<p:commandButton actionListener="#{testGroupController.saveNew}" value="#{bundle.Save}" update="display,:TestGroupListForm:tree,:growl" oncomplete="handleSubmit(xhr,status,args,TestGroupCreateDialog);"/>
<p:commandButton value="#{bundle.Cancel}" onclick="TestGroupCreateDialog.hide()"/>
</h:panelGroup>
</h:form>
</p:dialog>
I want that click on
<p:commandButton id="createButton#{node.getIdTestGroup()}" icon="ui-icon-plus" value="#{bundle.Create}" update="tree" oncomplete="TestGroupCreateDialog.show()"/>
Will set value of:
<h:inputHidden id="parentId" value="#{testGroupController.selected.parentId}" />
UPDATE
I have to use action listener testGroupController.nodeListener to set parentId of the new item.
<p:commandButton process="#this" id="createButton" actionListener="#{testGroupController.nodeListener}" icon="ui-icon-plus" value="#{bundle.CreateGroup}" update=":TestGroupCreateForm" oncomplete="TestGroupCreateDialog.show()">
<f:attribute name="rawParentId" value="#{node.getIdTestGroup()}" />
</p:commandButton>
You can add parentId to the existing update= attribute like so:
update="tree parentId"
This will render parentId and set its value to testGroupController.selected.parentId.
Edit
You can process any values from the UI to the been too, by using:
process="myInputId"
Example
<h:form>
<h:inputText id="input"
value="#{bean.value}" />
<h:outputText id="output"
value="#{bean.value}" />
<p:commandButton process="input"
update="output"
value="Submit" />
Upon clicking your button, the value of id="input" will be set in bean.value (as ordered by process="input"). Next your id="output" will be rendered (or updated) with bean.value (as ordered by update="output").

Resources