I'm trying to have multiple h:forms on a page which are rendered with a ui:repeat component. If I have only one generated h:form, everything works perfect. If I have multiple h:forms, only the latest h:form will work! (If I try to submit another form then the last, only null is passed trough my service!)
<ui:repeat var="element" value="#{myService.elementList}">
<rich:simpleTogglePanel switchType="client"
label="#{element.codeElement} - #{element.description}"
opened="#{myService.isUiSelected(element)}"
onexpand="expand#{element.codeElement}()"
oncollapse="collapse#{element.codeElement}()">
<h:form id="newKindForm">
<a:commandLink ajaxSingle="true" id="idLink" onclick="#{rich:component('newTargetPanel')}.show()">
<a:commandButton id="myButton"
value="new Form"
action="#{myService.newForm(element)}"/>
</a:commandLink>
</h:form>
<rich:modalPanel id="newTargetPanel" autosized="true" width="450">
<f:facet name="header">
<h:outputText value="My Pannel Title" />
</f:facet>
<f:facet name="controls">
<h:panelGroup>
<h:graphicImage value="/img/close.png"
id="hidelink"
styleClass="hidelink" />
<rich:componentControl for="newTargetPanel"
attachTo="hidelink"
operation="hide"
event="onclick" />
</h:panelGroup>
</f:facet>
<!-- THIS IS THE PROBLEMATIC FORM -->
<h:form>
<a:include viewId="../myRepeatableForm.xhtml" />
</h:form>
</rich:modalPanel>
</ui:repeat>
Some suggestion?
Thank You
you can contain everything in a single form, and use execute attribute to submit only the elements you want. like this:
<h:form id="newKindForm" prependId="false">
<ui:repeat id="newKindRepeat" var="element"
value="#{myService.elementList}" varStatus="varStatus">
<h:panelGroup id="newKindPanel">
<a:commandButton id="myButton"
execute="newKindRepeat:#{varStatus.index}:newKindPanel"
onclick="#{rich:component('newTargetPanel')}.show()"
value="new Form"
action="#{myService.newForm(element)}"/>
</h:panelGroup>
</ui:repeat>
</h:form>
please notice prependId of h:form, id and varStatus of ui:repeat, execute of a:commandButton.
btw, supposing that a: stands for ajax4jsf, i wouldn't recommend using commandButton nested in commandLink.
Is #{myService.elementList} a List ? If so, I'm not sure if that will work. Try using javax.faces.model.DataModel instead. Be sure to read the documentation carefully. It works something like this:
public Datamodel getElements(){
if(elements == null)
elements = new ListDataModel(getElementList());
return elements;
}
public List<Element> getElementList(){
elementList = foo(); // load the elements in your List like you did before
return elementList;
}
in your view: <ui:repeat var="element" value="#{myService.elements}">
I'm not familiar with RichFaces, this is the only suggestion I can make.
Related
This is the main view which contains the draggable items. In this view I have a ui:include for including a UI fragment that also has the drop area.
mainView.xhtml
<p:dataList id="outerList" var="varOuter" value="#{myVO.getOuterList()}">
<div>
<span>#{varOuter.someVal}</span>
</div>
<p:dataList id="innerList" var="innerVar" value="#{myVO.getInnerList()}">
<div class="crew-list">
<h:form>
<h:panelGroup id="draggableItem" layout="block">
<span>#{innerVar.someVal}</span>
</h:panelGroup>
<p:draggable for="draggableItem" opacity="0.5" scope="ab"
revert="true" helper="clone" appendTo="#(body)" zindex="4" >
</p:draggable>
</h:form>
</div>
</p:dataList>
</p:dataList>
...
<ui:include src="fragment.xhtml">
<ui:param name="param" value="#{paramVal}" />
</ui:include>
fragment.xhtml
<p:dataList id="list" var="pos" value="#{myVO.getPositions()}" rowIndexVar="rowIndex">
<ui:fragment rendered="#{!pos.isFilled()}">
<h:panelGroup layout="block" id="dropArea">
<span>Drop Here</span>
</h:panelGroup>
<p:droppable for="dropArea" hoverStyleClass="active"
scope="ab" datasource=":outerList:innerList">
<p:ajax listener="#{crewChangeVO.onDrop}" update="list" />
<f:attribute name="index" value="#{rowIndex}" />
</p:droppable>
</ui:fragment>
</p:dataList>
Now the problem that I run into is that, I am unable to map the datasource on the droparea correctly. Without datasource the drag-drop works but I don't get the data (dragged object) in my bean method and I need a way to know which object was dragged.
Would appriciate any input on how to achive this functionality.
Update
Using a single(non-nested) dataList as the source with a form outside it works. But the problem is that it doesn't work for a nested list. So, for now I am proceeding with design changes and removing the nested list.
I have a JSF application using Primefaces 3.5. I have a page where after click in a commandButton I call a method in Managed Bean which will fill a list that will be showed in fields tblPerfis and txtPerfis below.
<ui:composition template="...">
<ui:define name="content">
<h:form id="formPrincipal">
<br />
<p:fieldset legend="Pesquisa de Perfil" >
<p:panelGrid columns="2" >
<f:facet name="footer">
<p:commandButton id="btnPesquisar"
actionListener="#{perfilAcessoMB.pesquisar}" value="Pesquisar"
update="tblPerfis txtPerfis pnlPerfis"
styleClass="ui-icon-search" />
</f:facet>
</p:panelGrid>
</p:fieldset>
<br />
<h:outputText id="txtPerfis" value="Perfis: #{perfilAcessoMB.perfis}" ></h:outputText>
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}" var="perfil" emptyMessage="Nenhum perfil encontrado." >
<p:column headerText="Nome">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
</p:dataTable>
<p:outputPanel id="pnlPerfis">
<p:fieldset id="resultadoPesquisa" legend="Resultado da Pesquisa">TESTE</p:fieldset>
</p:outputPanel>
</h:form>
</ui:define>
</ui:composition>
The called method is the follow:
#ManagedBean
#ViewScoped
public class PerfilAcessoMB {
public void pesquisar(ActionEvent event) {
// Fill perfis List
}
}
At principle, it works as waited. My problem happens when I want add rendered attribute:
<h:outputText id="txtPerfis" value="Perfis: #{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" ></h:outputText>
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" var="perfil" emptyMessage="Nenhum perfil encontrado." >
<p:column headerText="Nome">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
</p:dataTable>
<p:outputPanel id="pnlPerfis" rendered="#{not empty perfilAcessoMB.perfis}">
<p:fieldset id="resultadoPesquisa" legend="Resultado da Pesquisa">TESTE</p:fieldset>
</p:outputPanel>
Even when there is results, these fields are not showed. Does someone have any idea what is happening here?
Thanks,
Rafael Afonso
EDIT
Following a workmate suggestion, I changed the code to put dataTable and outputText inside outputPanel. The commandButton will reference the outputPanel but the rendered attibute will be put in datatable and outputText.
<p:commandButton id="btnPesquisar"
actionListener="#{perfilAcessoMB.pesquisar}" value="Pesquisar"
update="pnlPerfis"
styleClass="ui-icon-search" />
<p:outputPanel id="pnlPerfis">
<h:outputText id="txtPerfis" value="Perfis: #{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" ></h:outputText>
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" var="perfil" emptyMessage="Nenhum perfil encontrado." >
<p:column headerText="Nome">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
</p:dataTable>
</p:outputPanel>
After this, the page worked as waited.
However, I still did not understand what happened. What is the explanation for this behaviour?
Your problem occurs because our table is not rendered it simply does not exist in your html code, that is not in this context to be found to update or another source.
When you shut a larger scope as the panel and force an update in this it forces the table to check the condition for rendering, if yes the code is written and can be seen without problems.
I have the following inside a richfaces modalpanel:
<ui:repeat id="al11" var="albumslistvalue1" value="#{AlbumDetailBean.getAlbumImagesList()}"
varStatus="albumslistvalue1Index">
<rich:modalPanel id="panel#{albumslistvalue1Index}" width="850" height="560">
<f:facet name="header">
<h:panelGroup>
<h:outputText value="Fotos"/>
</h:panelGroup>
</f:facet>
<f:facet name="controls">
<h:panelGroup>
<h:graphicImage value="/img/modal/close.png" styleClass="hidelink" id="hidelink"/>
<rich:componentControl for="panel" attachTo="hidelink" operation="hide"
event="onclick" />
</h:panelGroup>
</f:facet>
<!-- content-->
<center>
<h:graphicImage value="img/cart/prior16.png" />
<h:graphicImage value="albums/#{albumslistvalue1.albumImageId}/med_#{albumslistvalue1.albumimagename}"/>
<h:graphicImage value="img/cart/next16.png" />
<h:commandLink id="comp" action="#{AlbumDetailBean.getCartAlbums()}">
<div>
<h:outputText value="Comprar" />
<f:param name="albumproductid" value="#{albumslistvalue1.id}" />
</div>
</h:commandLink>
</center>
</rich:modalPanel>
<h:outputLink value="#" id="link">
<!-- Show Modal Panel -->
<h:graphicImage id="image" url="albums/#{albumslistvalue1.albumImageId}/mini_#{albumslistvalue1.albumimagename}"
width="100px" height="auto" />
<rich:componentControl for="panel#{albumslistvalue1Index}" attachTo="link"
operation="show" event="onclick" />
</h:outputLink>
</ui:repeat>
and getCartAlbums() method:
public List getCartAlbums() {
boolean status = false;
AlbumImpl bean1 = new AlbumImpl();
String productidval = ((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()).getParameter("albumproductid");
AlbumDetailBean albums = (AlbumDetailBean) bean1.bo_getAlbumImageDetails(productidval);
if(albums != null) {
cartAlbumDetails.add(albums);
setId(albums.getId());
setAlbumname(albums.getAlbumname());
setSchoolId(albums.getSchoolId());
setAlbumImageId(albums.getAlbumImageId());
setAlbumimagename(albums.getAlbumimagename());
// setAlbumimage(albums.getAlbumimage());
setListPrice(albums.getListPrice());
setAvailableQty(albums.getAvailableQty());
setTotalAmount(albums.getTotalAmount());
setProductcode(albums.getProductcode());
setListpricevalue(albums.getListpricevalue());
setProductsize(albums.getProductsize());
setQtyvalue(albums.getQtyvalue());
setTotalpricevalue(albums.getTotalpricevalue());
setProductid(albums.getProductid());
setShipPrice(albums.getShipPrice());
}
return cartAlbumDetails;
}
I'm using someone else's code, so i didn't write the getCartAlbums() method, but it basically add the select image to the cart, it's working, the images are added to the cart correctly, but the modalpanel still closes
I think you're using JSF 1/RF3? getCartAlbums() is returning a list, is this right? My JSF 1 knowledge is from the distant past but it doesn't look right.
However, the problem is that the h:commandLink is doing a full page submit, a POST request which reloads the page with the results of the postback (the response to the POST request). So after the button is pushed you see the screen redraw and what you're seeing is the page in the same state (albeit with updated values) as it was in when you first loaded it, which is without a modalPanel.
To remedy the problem you want to use a4j:commandLink to perform an ajax partial submit. I'm not sure if RF3 has execute= and render= attributes on the a4j:commandLink component or whether you have to use a4j:support as a child component, but I'm sure you can find out. You use execute= to specify which components values are submitted in the body of the ajax POST request, and render= to specify which components are updated after the postback is received.
I am trying to submit values in a pop-up panel inside another panel that has a submit/action event. But before opening pop-up panel I need to invoke a function on my managed bean that create a new entity object. The outer panel has the only h:form, since you can't nest them. I have wrapped the pop-up panel in a a4j:region to submit only this part when the use submits the values inside the pop-up panel. This works, but not the execution of the preparing function that need to be invoked when the pop-up panel executes. I have tried a4j:commandLink but that component don't work together with the rich:popupPanel (strange since both of them are Richfaces components?!). So I have to relay on the h:commandLink and use ajax.
How can I invoke a function on my managed bean when the link to open/render the pop-up panel fires?
(What is the correct pattern for this?)
PS. The initial question has changed, but not the problem concerning submitting values in a pop-up panel.
Part of the xhtml file:
<h.form>
...
<a4j:region>
<rich:popupPanel id="popup_sys_user_req" modal="false" autosized="true" resizeable="false">
<f:facet name="header">
<h:outputText value="Request New Sector/Category" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#"
onclick="#{rich:component('popup_sys_user_req')}.hide(); return false;">
X
</h:outputLink>
</f:facet>
<h:panelGrid columns="2">
<h:outputLabel value="Request New:" />
<h:selectOneMenu id="sys_req_type" value="#{userController.selectedSysUserRequest.sysrequesttype}" required="true" >
<f:selectItems value="#{userController.getSysRequestTypeItems('SECTOR_CATEGORY')}">
</f:selectItems>
</h:selectOneMenu>
<h:outputLabel value="Description:" />
<h:inputTextarea id="user_req_desc" value="#{userController.selectedSysUserRequest.description(desc)}" required="true" requiredMessage="Decription is missing" />
</h:panelGrid>
<a4j:commandButton action="#{userController.CreateSysUserRequest()}" value="Send Request" execute="sys_user_req_form" oncomplete="#{rich:component('popup_sys_user_req')}.hide(); return false;"/>
</rich:popupPanel>
</a4j:region>
</h:form>
The commandLink (re-edit)
<h:commandLink actionListener="#{userController.prepareCreateSysRequest}" value="Request New Sector/Category">
<f:ajax execute="popup_sys_user_req #this" render="popup_sys_user_req">
<rich:componentControl id="popup_ctr" event="click" target="popup_sys_user_req" operation="show"/>
</f:ajax>
</h:commandLink>
----------------------------
//Managed Bean:
public void prepareCreateSysRequest(ActionEvent event ) {
selectedSysUserRequest = new Sysuserrequest();
JsfUtil.log("Prepare Create System User Request");
}
This post continues the dicussion about the pop-up panel.
Greetings Chris.
If I understand correctly you want to submit all form elements inside popupPanel but not outside the panel when you invoke someAction1? I can think of two ways to do this:
1. a4jcommandButton has a limitToList attribute, you can list which components you want to be updated on the server
2. create your popupPanel outside of the first form and then use its own form:
<h:form>
...
<a4j:commandButton action="someAction2"...
</h:form>
<rich:popupPanel>
<h:form>
...
<a4j:commandButton action="someAction1"...
</h:form>
</rich:popupPanel>
Update
If you are using RichFaces 4 you can replace the limitToList attribute with limitRender
The problem is that the popup isn't a child of the form in jsf, you only need to use the domElementAttachment attribute to change that. So your code would look like this:
<h.form>
...
<a4j:region>
<rich:popupPanel id="popup_sys_user_req" modal="false" autosized="true" resizeable="false" domElementAttachment="form">
<f:facet name="header">
...
I'lve already searched, but even implementing the solutions I've found, I was not able to get this working. I select a row in a datatable and click on delete button to delete the selected object, but the object gets deleted but the datatable is not updated. Here's my code:
<h:form id="formPesquisa">
...
<h:panelGroup id="panelToRender" layout="block">
<h:panelGroup id="panelDataTable" rendered="#{not empty bean.dataList}" layout="block">
<div id="dataTableRegion">
<p:panel id="panelBtnsUp" styleClass="cleanPanel">
<ui:include src="/templates/btnDataList.xhtml" />
</p:panel>
<h:panelGroup id="panelTableHolder" layout="block">
<p:dataTable id="dataTableBusca" value="#{bean.dataList}" var="entidade"
rendered="#{not empty bean.dataList}" paginator="true" style="width:100%;"
selection="#{bean.entidadesSelecionadas}" onRowSelectUpdate="panelBtnsUp,panelBtnsDown,dataTableBusca"
onRowUnselectUpdate="panelBtnsUp,panelBtnsDown,dataTableBusca" rowUnselectListener="#{bean.rowUnselectListener}" selectionMode="multiple">
<p:column>
<p:graphicImage url="/icons/checkbox_no.png" rendered="#{!bean.containsSelection(entidade)}" />
<p:graphicImage url="/icons/checkbox_yes.png" rendered="#{bean.containsSelection(entidade)}" />
</p:column>
<ui:insert name="colunasPesquisa" />
</p:dataTable>
</h:panelGroup>
<p:panel id="panelBtnsDown" styleClass="cleanPanel">
<ui:include src="/templates/btnDataList.xhtml" />
</p:panel>
</div>
</h:panelGroup>
</h:panelGroup>
....
</h:form>
And the Delete Button is in the included file:
<div style="margin:5px 0;">
<p:commandButton value="#{msg['commons.excluir']}" image="delete" disabled="#{bean.disableDelete()}" action="#{bean.delete}" update="panelDataTable" />
<p:commandButton value="#{msg['commons.editar']}" image="edit" disabled="#{bean.disableEdit()}" action="#{bean.prepareEdit}" ajax="false" />
</div>
I already tried:
update="dataTableBusca"
update="panelTableHolder"
update="formPesquisa:dataTableBusca"
update="formPesquisa:panelTableHolder"
What am I doing wrong???
Thanks for any help.
The first two approaches will only work if your button and the updated elements are siblings.
For the third and the fourth approach you have to traverse all containing elements in order to get the right id. You panelTableHolder is inside two other h:panelGroup (panelToRender, panelDataTable) and a div (dataTableRegion).
Furthermore to make sure that you start from highest level, prepend a : before the form id.
Try this:
update=":formPesquisa:panelToRender:panelDataTable:dataTableRegion:panelTableHolder"
You could check in the rendered html if this is the correct path for your panelTableHolder.