JSF - Updating repeated element from repeat - jsf

I have a code that is little bit odd but it goes something like this:
<h:form id="groupsForm">
<ui:repeat value="#{groupsContainer.groups}" var="group">
<p:outptuText value="#{group.name}" />
<p:card id="group">
<ui:repeat value="#{group.users}" var="user">
<p:outputText value="#{user.name}" />
<p:commandButton
value="Delete"
process="#this"
actionListener="#{groupsController.deleteUserFromGroup(group, user)}"
update="group"
/>
</ui:repeat>
</p:card>
</ui:repeat>
</h:form>
Sadly that command button can't find the group in which it is when rendering the page ending with Java error:
org.primefaces.expression.ComponentNotFoundException: Cannot find component for expression "group" referenced from "groupsForm:j_idt42:0:j_idt73:0:j_idt102".
It seams to me that you can't reference a repeated component from another repeat that is in it. I tried to play with the ids and wrap some components in <h:panelGroup/> but that didn't helped.
Then I realised that I don't need to update the whole <p:card/> and it should be enough to update only the second <ui:repeat/>, so I did this:
<h:form id="groupsForm">
<ui:repeat value="#{groupsContainer.groups}" var="group">
<p:outptuText value="#{group.name}" />
<p:card id="group">
<h:panelGroup id="users">
<ui:repeat value="#{group.users}" var="user">
<p:outputText value="#{user.name}" />
<p:commandButton
value="Delete"
process="#this"
actionListener="#{groupsController.deleteUserFromGroup(group, user)}"
update="users"
/>
</ui:repeat>
</h:panelGroup>
</p:card>
</ui:repeat>
</h:form>
but the result was pretty much the same with only different ids:
Cannot find component for expression "users" referenced from "groupsForm:j_idt42:0:j_idt73:0:j_idt102".
So my question is: Can I somehow update repeated component with repeat from inside of the second repeat?

Related

datasource mapping doesn't work when droppable is in nested dataList

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.

a4j:commandButton doesn't render the element

I've got a JSF page with <rich:tabPanel> which contains 4 tabs.
On the 4th tab I'm trying to use <a4j:commandButton> to execute the action and render resulTable.
Here is the shorten example
<rich:tab header="Journal">
<h:form id="filterForm">
<a4j:jsFunction name="submitByEnter"
action="#{smsLogList.refresh}" render="smsTable" />
<s:div id="divSearch">
<rich:collapsiblePanel header="#{messages['search']}"
switchType="client">
<h:panelGrid column="1">
<s:decorate template="/layout/edit.xhtml">
<ui:define name="label">Package number</ui:define>
<h:inputText id="packNum" style="width:200px"
value="#{smsLogList.packNum}">
<a4j:ajax event="keyup" listener="#{smsLogList.refresh}"
ignoreDupResponses="true" requestDelay="1500"
render="smsTable" />
</h:inputText>
</s:decorate>
<!---some other search elements-->
<s:div styleClass="actionButtons">
<a4j:commandButton id="search" value="#{messages['search']}"
render="smsTable" action="#{smsLogList.go}" />
<a4j:commandButton id="reset" value="#{messages['clear']}"
onclick="document.getElementById('filterForm').reset();"
action="#{smsLogList.clear}" render="divSearch,smsTable" />
</s:div>
</h:panelGrid>
</rich:collapsiblePanel>
</s:div>
<!--- results table-->
<h:panelGrid id="smsTable">
<s:div>
<rich:dataTable value="#{smsLogList.resultList}" var="sms"
id="table" rendered="#{not empty smsLogList.resultList}">
<rich:column>
<f:facet name="header">Type</f:facet>
<h:outputText value="#{sms.smsType}" />
</rich:column>
<!---- some other columns-->
</rich:dataTable>
<rich:dataScroller for="table" />
</s:div>
</h:panelGrid>
</h:form>
</rich:tab>
So, when I'm clicking on the <a4j:commandButton> - nothing happens, but if I'm switching to the other tab and back - the result is as necessary.
I tried to change a4j to <h:commandButton>, but after it's pressed the page switches to the first tab.
Is any solution how to work this out?
The solution is quite simple.
I used <h:form> inside other <h:form>. It will not work anyway. When I remove internal - the jsf works smooth and as it should.

multiple h:forms in ui:repeat

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.

JSF 2 + Primefaces - Update Not Working

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.

PrimeFaces button in Tab Doesn't Navigate

I'm developing this project using JSF 2.0, NetBeans 6.9.1, GlassFish 3.1, Mojarra 2.0.3, and PrimeFaces 2.2-RC2.
My question is similar to this question, but even though I was able to make one of my buttons work, the other one does not. Here's my situation: I have a dataTable with a column containing two links, one to edit line data, one to view line data. Clicking either the "Edit" or "View" link takes you to a detail page with <h:panelGrid> components inside <p:tabView> components. My detail page has two <p:tabView> components, one for editing, one for just viewing data. Which one you see depends on the <c:if> statements. The button in the first <p:tabView> on the page (by that I mean first working your way down from the top) works as I would like it to, this happens to be the "Edit" component. The button in the other <p:tabView> does not work. I set up break points and went through the debugger, the second button doesn't seem to fire an ActionEvent regardless of what I try. Here's my code for the page:
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{userDetailBean.selectedUserId}" />
<f:viewParam name="action" value="#{userDetailBean.view}" />
</f:metadata>
</ui:define>
<ui:define name="main_base_content_top">
<h:form>
<p:toolbar>
<p:toolbarGroup align="left">
<h:commandButton value="Return to User List" action="user_grid" />
</p:toolbarGroup>
</p:toolbar>
</h:form>
</ui:define>
<ui:define name="main_base_content">
<c:if test="#{empty userDetailBean.view}">
<h:form>
<table align="center">
<tr>
<td>
<p:tabView>
<p:tab title="#{msgs.UserDetailTabTitle}">
<h:panelGrid columns="4">
<h:outputLabel value="#{msgs.UserDetailFirstName}" for="fname" />
<h:inputText id="fname" value="#{userDetailBean.firstName}" />
<h:outputLabel value="#{msgs.UserDetailJobTitle}" for="jtitle" />
<h:inputText id="jtitle" value="#{userDetailBean.jobTitle}" />
<h:outputLabel value="#{msgs.UserDetailLastName}" for="lname" />
<h:inputText id="lname" value="#{userDetailBean.lastName}" />
<h:outputLabel value="#{msgs.UserDetailEmployeeId}" for="empid" />
<h:inputText id="empid" value="#{userDetailBean.id}" />
<h:outputLabel value="#{msgs.UserDetailDateOfHire}" for="doh" />
<h:inputText id="doh" value="#{userDetailBean.DOH}" />
<h:outputLabel value="#{msgs.UserDetailLocation}" for="location" />
<h:inputText id="location" value="#{userDetailBean.location}" />
<h:outputLabel value="#{msgs.UserDetailStatus}" for="status" />
<h:inputText id="status" value="#{userDetailBean.status}" />
<h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden />
<h:outputLabel value="#{msgs.UserDetailComments}" for="comments" />
<h:inputTextarea id="comments" value="#{userDetailBean.comments}" />
<h:inputHidden />
<p:commandButton ajax="false" action="#{userDetailBean.submitChanges()}" value="Submit Changes" />
</h:panelGrid>
</p:tab>
</p:tabView>
</td>
</tr>
</table>
</h:form>
</c:if>
<c:if test="#{! empty userDetailBean.view}">
<h:form>
<table align="center">
<tr>
<td>
<p:tabView>
<p:tab title="#{msgs.UserDetailViewTabTitle}">
<h:panelGrid columns="4">
<h:outputLabel value="#{msgs.UserDetailFirstName}" for="fname" />
<h:outputText id="fname" value="#{userGridBean.selectedUser.firstName}" />
<h:outputLabel value="#{msgs.UserDetailJobTitle}" for="jtitle" />
<h:outputText id="jtitle" value="#{userGridBean.selectedUser.jobTitle}" />
<h:outputLabel value="#{msgs.UserDetailLastName}" for="lname" />
<h:outputText id="lname" value="#{userGridBean.selectedUser.lastName}" />
<h:outputLabel value="#{msgs.UserDetailEmployeeId}" for="empid" />
<h:outputText id="empid" value="#{userGridBean.selectedUser.id}" />
<h:outputLabel value="#{msgs.UserDetailDateOfHire}" for="doh" />
<h:outputText id="doh" value="#{userGridBean.selectedUser.DOH}" />
<h:outputLabel value="#{msgs.UserDetailLocation}" for="location" />
<h:outputText id="location" value="#{userGridBean.selectedUser.location}" />
<h:outputLabel value="#{msgs.UserDetailStatus}" for="status" />
<h:outputText id="status" value="#{userGridBean.selectedUser.status}" />
<h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden />
<h:outputLabel value="#{msgs.UserDetailComments}" for="comments" />
<h:outputText id="comments" value="#{userGridBean.selectedUser.comments}" />
<h:inputHidden /> <h:inputHidden /> <h:inputHidden />
<p:commandButton onclick="submit()" ajax="false" action="#{userDetailBean.navigation()}" value="Retur to User Grid" />
</h:panelGrid>
</p:tab>
</p:tabView>
</td>
</tr>
</table>
</h:form>
</c:if>
</ui:define>
</ui:composition>
</body>
I've tried everything I can think of for the second button: ajax="false"; onclick="submit()"; ajax="false" onclick="submit"; I've tried implicit navigation with a redirect as well as a navigation rule with a redirect. The action methods userDetailBean.submitChanges() and userDetailBean.navigate() both return the same string, which corresponds to a navigation rule in my faces-config file. The submitChanges method gets called, but my navigate method does not. I'm not filling the fields with any data at this point, I'm just trying to get the basic navigation to work. Why isn't my commandButton on the second tabView working?
Another reason that a commandbutton isn't been invoked is that the rendered attribute of the button or one of its parents evaluated false during apply request values phase of the form submit.
You have actually none, but those <c:if> tags does similar thing, only during view build time instead of view render time. The view params are not applied during building the view, but only thereafter. That's exactly why #{userDetailBean.view} is always empty.
I have never used such a construct with <c:if>, but I've had similar views like this where this all just works with a #ViewScoped bean where the rendering property is been applied on a fullworthy JSF component instead of <c:if>.
As first step, get rid of <c:if>s and move their tests into rendered attribute of the <h:form>s they are wrapping:
<h:form rendered="#{empty userDetailBean.view}">
...
</h:form>
<h:form rendered="#{not empty userDetailBean.view}">
...
</h:form>
If in vain (I guess that this will fail because you aren't using ajax and the viewparams are not preserved) and the bean is indeed #RequestScoped, then you need to mark it #ViewScoped to preserve the rendering conditions.
Related questions:
JSF h:commandLink is not being invoked
Unrelated to the problem, I'd rather use <h:panelGroup /> instead of <h:inputHidden /> to "fill" the empty cells of the table. They are cheaper to encode and decode and also ends in better HTML.

Resources