hide component, then show it, values are not saved - ajax

I have a JSF 2.0 web app with ajaxified tabs.
To switch tabs I show one and hide the others (Either with a conditional render="#{x==y}" or with with display:none/block through conditional styleClass`ing.
In either case I get the tabs to show or hide correctly.
The problem is that the values entered in the input boxes are not retained throw a hide/show of a tab (In other words, if you enter some values in tab 1, go to tab 2 and back to tab 1, the values are not retained).
I use this <f:ajax> tag on tab selection (ignited by a hash change event)
<h:form id="processFragment" prependId="false" class="hide">
<h:inputText id="fragment" value="#{fbean.fragment}">
<f:ajax event="change" execute="contentSection" listener="#{fbean.processFragment}"
render="contentSection" />
</h:inputText>
</h:form>
<div>
<h:form id="contentSection">
<ui:insert name="content" />
</h:form>
</div>
Thanks!
The code the display the tab bar and the tab contents:
<ui:define name="content">
<f:view>
<h:panelGroup styleClass="navBar">
<ul>
<ui:repeat value="#{hello.tabList}" var="tab">
<li onclick="window.location='\##{tab.tabHash}'"><h:panelGroup
styleClass="#{hello.chose == tab.tabHash?'activeTab':''}">
<h:outputText value="#{tab.tabName}" />
</h:panelGroup>
</li>
</ui:repeat>
</ul>
</h:panelGroup>
<h:panelGroup id="contentPanels" styleClass="tabContentBar">
<c:forEach items="#{hello.tabList}" var="tab">
<h:panelGroup rendered="#{hello.chose == tab.tabHash}">
<!-- <h:panelGroup styleClass="#{hello.chose == tab.tabHash?'shownTabContents':'hiddenTabContents'}"> -->
<ui:include src="#{tab.tabFile}" />
</h:panelGroup>
</c:forEach>
</h:panelGroup>
</f:view>
</ui:define>
Finally, the contents of the specific tab:
<h:outputText value="TESTING 1" />
<h:panelGroup styleClass="formField">
<h:outputText value="Enter Value:" />
<h:inputText value="#{general.name}" />
</h:panelGroup>
UPDATE
Just noticed that even if I don't hide the tabs and press a button, the value is reset. Investigating...

The values will only be retained if you use a view scoped bean and the desired form is been submitted to the server side during (or right before) tab navigation.
As an alternative, you could render all tabs at once and use only JS/CSS to show/hide tab contents. CSS-hidden inputs will still be submitted to the server side.

Related

Strange behavior with f:ajax: Toggle between views does not update rendered code in browser if <ui:repeat> has an <h:outputText> with escape="false"

I want to switch between two views and report two lists outputs on each view.
Toggle between views uses a <h:commandLink> with an <f:ajax> element.
Each view generates the output of the lists with <ui:repeat>
The output works fine, if the <h:outputText> within the <ui:repeat> does not specify the escape attribute.
After adding escape="true" to the <h:outputText> the following happens:
After clicking the <commandLink> the <commandLink> the browser does not update the rendered output.
After clicking the myController.toggleView changes listData.showFirst (boolean)
After clicking the <commandLink> the source code of the website changes to what should be there.
Summary: Clicking the <commandLink> updates the outputed source code, but the browser does not update the output, when the <h:outputText> in the <ui:repeat> uses the attribute escape="true".
Here the code:
<h:form prependId="false">
<h:commandLink actionListener="#{ myController.toggleView }" value="Click">
<f:ajax render="#form" />
</h:commandLink>
<h:panelGroup rendered="#{ listData.showFirst }" id="firstView">
<ui:repeat var="house" value="#{ listData.houses }">
<h:outputText value="#{ house.description }" escape="false" />
</ui:repeat>
</h:panelGroup>
<h:panelGroup rendered="#{ !listData.showFirst }" id="secondView">
<ui:repeat var="street" value="#{ listData.streets }">
<h:outputText value="#{ street.description }" escape="false" />
</ui:repeat>
</h:panelGroup>
</h:form>
Any ideas?

richfaces select menu rendering triggered by event

I have popup window that is used in few tabs and popup uses some params from tabs such as dialogContainerId and dialogId.
I have "select item" menu and "refresh items" button near it. So when user click button i want to get new item list for select menu. Select menu works as expected, but "refresh" button is not. I'm sure that listener on refresh button works well and can see updated item list if new items appear in database. But select menu doesn't update. It seems like render attribute on f:ajax doesn't work or there is id mismatch. I checked page and found nothing. Ids look well. I tried constant ids, and tried to move id to parent tag, but always have got same result - select menu is not re-rendered.
Does any one have ideas or suggestions? Thanks in advance.
Here is source page:
<ui:composition>
<h:panelGroup id="#{dialogContainerId}">
<rich:popupPanel id="#{dialogId}" autosized="true" modal="true" domElementAttachment="parent">
<h:panelGrid id="#{dialogId}commonControls" columns="3">
<!-- more input tags -->
<h:outputLabel value="Create dialog" />
<h:panelGroup>
<rich:select id="#{dialogId}expenseItem" value="#{expenseItemInstanceBean.selectedExpenseItemId}"
selectFirst="true" required="true" requiredMessage="Required">
<f:selectItems value="#{expenseItemInstanceBean.expenseItemsAsList}"
var="item" itemValue="#{item.id}" itemLabel="#{item.name}" />
</rich:select>
<h:graphicImage library="icons" name="refresh_16x16.gif" title="Refresh">
<f:ajax event="click" execute="#this" render="#{dialogId}expenseItem"
listener="#{expenseItemInstanceBean.refreshExpenseItems()}" />
</h:graphicImage>
</h:panelGroup>
<h:messages for="#{dialogId}expenseItem" />
<!-- more input tags -->
</h:panelGrid>
<!-- button tags tags -->
</rich:popupPanel>
</h:panelGroup>
</ui:composition>
And part of rendered html page:
<td>
<div class="rf-sel" id="idForm:wrkSchedDialogexpenseItem">
<!-- here is my list and additional autogenerated jsf tags -->
</div>
<img id="idForm:j_idt42" src="/logistics-web/javax.faces.resource refresh_16x16.gif.xhtml?ln=icons"
alt="" style="vertical-align: bottom" title="Refresh"
onclick="mojarra.ab(this,event,'click','#this','idForm:wrkSchedDialogexpenseItem');return false"
class="linkLikeCursor" name="idForm:j_idt42"/>ev
</td>

Richfaces <a4j:ajax> and <rich:popupPanel> "conflict"

I've stumbled upon a strage behavior of richfaces. Some background about my view structure:
It's mainly a <rich:extendedDataTable> where a click on a row displays info about it on a <a4j:outputPanel>
Also, each row has a context menu with items like "Create", "Edit", etc... that pops a <rich:popupPanel>
The component structure is this:
<h:panelGrid columns="2">
<h:column>
<rich:dataScroller for="testTable" maxPages="7"/>
<rich:extendedDataTable id="testTable" value="#{testController.items}" rendered="#{testController.items.rowCount != 0}"
selection="#{testController.selectedRow}" noDataLabel="No results to show" var="test" rows="20"
style="width: 790px" selectionMode="single">
<a4j:ajax execute="#form"
event="selectionchange"
listener="#{testController.selectionListener}"
render=":res"/>
{columns to display}
</rich:extendedDataTable>
</h:column>
<a4j:outputPanel id="res">
<rich:panel header="Selected Rows:" rendered="#{not empty testController.selectedRows}">
<rich:list type="unordered" value="#{testController.selectedRows}" var="t">
<h:outputText value="#{t.name}"/>
<br/>
<h:outputText value="#{t.details}" converter="#{testConverter}"/>
</rich:list>
</rich:panel>
</a4j:outputPanel>
</h:panelGrid>
<rich:contextMenu target="testTable" mode="ajax" id="contextMenu">
<rich:menuItem label="Edit" render="popupEdit" oncomplete="#{rich:component('popupEdit')}.show();" mode="ajax"/>
</rich:contextMenu>
<rich:popupPanel id="popupEdit" modal="true" autosized="true" resizeable="false" moveable="false" domElementAttachment="form">
<rich:hotKey key="esc" onkeyup="#{rich:component('popupEdit')}.hide(); return false;"/>
<f:facet name="header">
<h:outputText value="Edit Test"/>
</f:facet>
<f:facet name="controls">
<h:outputLink value="#" onclick="#{rich:component('popupEditar')}.hide(); return false;">
<h:graphicImage value="/resources/css/images/fechar_janela.png" width="20" height="20"/>
</h:outputLink>
</f:facet>
<h:panelGrid id="popupEditContent" columns="2">
... {display of info}
<a4j:commandButton value="Salvar" actionListener="#{testeController.update()}" render="tabelaTestes, contextMenu"/>
<h:panelGroup id="messagePanel" layout="block">
<rich:messages ajaxRendered="true" />
</h:panelGroup>
</h:panelGrid>
</rich:popupPanel>
And now the strange behaviour (using NetBeans):
Deploy the app from NetBeans;
Open the URL of the deployed project on browser (Firefox) . The <a4j:ajax> inlined in the table doesn't work, I know this because the 'testController.selectionListener' is not called and the details are not displayed (it sets the attribute current in the backing bean). The contextMenu works but the popupPanel shows null or empty properties in all fields (the current attribute is not set);
Go back to the IDE, remove all the <rich:popupPanel> section and save the file;
Back in the browser, hit F5 and click a row. Now the <a4j:ajax> works and calls testController.selectionListener, showing the details in <a4j:outputPanel>. The context menu works but (obviously) the panel does not pop;
In the IDE, put back the <rich:popupPanel> section and save the file;
Now refresh the page again, and everything works, details are shown and the Edit pop up shows the right info of the selected row.
I have tried deploying it without the <rich:popupPanel> section and the selecionListener gets called. I think that the problem is deploying the page with both <a4j:ajax> and <rich:popupPanel> sections, hence the "conflict".
I took the structure from the richfaces showcase and made changes. I noticed that in the showcase, the <rich:popupPanel> is placed outside the <h:form> tag, wich in my project is placed in the template.xhtml (so a topmenu page works). Is it possible that the error is caused by this placement?
Could this be considered a bug to file in the richfaces project or am I missing something there?
Is there a workaround or solution?
Thank you very much!
I think I have solved it. I set the id attribute to "form" in the <h:form> tag, in template.xhtml, so now it looks like this:
<h:body>
<h:form id="form">
<div id="top" class="top">
<ui:insert name="top">Top</ui:insert>
</div>
<div id="content" class="center_content">
<ui:insert name="content">Content</ui:insert>
</div>
</h:form>
</h:body>
It was the only change I made and now all the components work at first post-deploy.
Edit: Found the solution when searching for another problem: JSF action call on secon click

Ajax not working with primefaces

In my JSF page I have form when I click submit button in the same page I need to show an static content. But When I click <p:commandbutton> nothing appears in the page. When I put ajax="false" then only action taken place but the Static content display in new page.
In my Backing bean I have used Session scoped. I am using JSF 2.0 and Primefaces 3.2.
My JSF Page.
<h:form>
<h:panelGroup rendered="#{not license.showForm}">
<p:panel header="License Key Request" >
<h:panelGrid columns="2" >
..
<h:outputText value="Bla bla"/>
..
<h:outputText value="Bla Bla" />
</h:panelGrid>
<TABLE>
..
<h:outputLabel for="name" value="Requestor Name : *" />
..
<p:inputText id="name" value="#{license.name}" required="true" requiredMessage="Name is required."/>
..
<h:outputLabel for="company" value="Company : * " />
..
<p:inputText id="company" value="#{license.company}" required="true" requiredMessage="Company is required."/>
..
</table>
<p:commandButton value="Form" id="btnAdd" process="#form"
action="#{license.add}" />
..
</table>
</p:panel>
</h:panelGroup>
<h:panelGroup rendered="#{license.showForm}" >
<h:outputText value="Bla Bla"/>
</h:panelGroup>
</h:form>
Your source code is somewhat confusing (e.g. you have two closing table tags). But I assume that you want to show the panelGroup at the bottom if the button is clicked.
The easiest way would be to add an update ="#form" to your commandButton:
<p:commandButton value="Form" id="btnAdd"
process="#form" update="#form"
action="#{license.add}" />
You don't need to update the whole form but only the specific component. Then you need to give the panelGroup an id attribute and use this attribute instead of #form. However, since it is not clear for me how your naming containers are organized, it could be puzzling to find the correct relative id.

how to do partial page rendering (center content) with jsf2 templating via ajax (from menu)

i have been struggling getting this to work for 2 weeks, I am trying to merge info from BalusC from these 2 posts to (link1 link2) to achieve partial page rendering of a center content area via a menu on the left. So the links on the left would update the center content via partial page rendering using <f:ajax> or maybe <a4j:ajax> via richfaces
------------------------------------------------------
| include1 link | |
| include2 link | center content like include1.xhtml |
| include3 link | |
------------------------------------------------------
my page-layout.xhtml (master template to be used by include1.xhtml, include2.xhtml,..)looks like this.
<h:body>
<div id="top" class="top">
<ui:insert name="top">page-layout default top content</ui:insert>
</div>
<div>
<div id="left">
<h:form id="navigationFormId">
<f:ajax render=":contentForm">
<h:commandLink value="include1"
action="#{navigationBean.setPage('include1')}" />
<p></p>
<h:commandLink value="include2"
action="#{navigationBean.setPage('include2')}" />
<p></p>
<h:commandLink value="include3"
action="#{navigationBean.setPage('include3')}" />
<p></p>
</f:ajax>
</h:form>
</div>
<div id="content">
<ui:insert name="content">
<h:panelGroup id="contentPanelGroup" layout="block">
<h:form id="contentForm">
<h:panelGroup rendered="#{navigationBean.page == 'include1'}">
<ui:include src="include1.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{navigationBean.page == 'include2'}">
<ui:include src="include2.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{navigationBean.page == 'include3'}">
<ui:include src="include3.xhtml" />
</h:panelGroup>
</h:form>
</h:panelGroup>
</ui:insert>
</div>
</div>
</h:body>
NavigationBean.java is defined as a ViewScoped bean via CDI with #Named
public class NavigationBean implements Serializable {
public NavigationBean() {}
public String getPage() {return page;}
public void setPage(String p) {page = p;}
private String page = "include1";
}
the included pages are file like include1.xhtml and include2.xhtml and should be loaded into center content when the left menu links are clicked, here is a sample include2.xhtml
<h:body>
<ui:composition template="page-template.xhtml">
<ui:define name="content">
include2
<h:form>
form components for include2
</h:form>
</ui:define>
</ui:composition>
</h:body>
I am getting FileNotFoundException, although the stack trace does not
tell which one, but removing the
<h:panelGroup rendered=".....>
<ui:include src="..." />
</h:panelGroup>
tags removes the exception. I think this is the proper implementation to accomplish this based on 2 of BalusC posts, but just can't get it to work.
The error you are getting suggests the include...xhtml page can not be found. Where are the files located? They should be in the same directory as the page-layout.xhtml file? To simplify everything I would just test if the include works, yuo can replace this:
<h:form id="contentForm">
<h:panelGroup rendered="#{navigationBean.page == 'include1'}">
<ui:include src="include1.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{navigationBean.page == 'include2'}">
<ui:include src="include2.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{navigationBean.page == 'include3'}">
<ui:include src="include3.xhtml" />
</h:panelGroup>
</h:form>
with:
<h:form id="contentForm">
<ui:include src="include1.xhtml" />
</h:form>
i was able to get a design via JSF2/Ajax and richfaces4 (other implementations would be ok I assume) where a left navigation menu item, implemented via templates, is able to render the center content of a template via ajax, preventing a full page refresh, and the flicker effect it has.
my navigationmenu.xhtml code looks like this
<ui:composition>
<h:form id="navigationFormId">
<rich:collapsiblePanel id="carrierCollapsibleId" header="Links that update center content" switchType="client">
<h:commandLink id="linkId1" action="/page1" value="Update Center Content with page1">
<a4j:ajax execute="#form" render=":centerContentDiv,:centerForm" />
</h:commandLink>
<br />
<h:commandLink id="linkId2" action="/page2" value="Update Center Content with page2">
<a4j:ajax execute="#form" render=":centerContentDiv,:centerForm" />
</h:commandLink>
</rich:collapsiblePanel>
...
</h:form>
I believe the render=":centerContentDiv,:centerForm" attribute for the a4j:ajax tags can be changed to just render=":centerForm" but have not tested that. I know the both work together however. also, i tried JSF2 ajax tags with white space between the IDs and got errors, so i went to richfaces 4.x's a4j and then could use commas if no space was used.
now, in order for this to work, each pageX.xhtml file, for example page1.xhtml would need to have <h:form id="centerForm">, here is an example of page1.xhtml
<ui:composition template="/templates/uiTemplate.xhtml">
<ui:define name="center_content">
<h:form id="centerForm">
<!-- put your components in here -->
</h:form>
</ui:define>
</ui:composition>
one limitation is each view that uses the template must define a <h:form id=centerForm" ...> otherwise JSF2 will complain it can't find the render target.
my uiTemplate.xhtml file has code for the header, footer, but the pertinent part that has the navigation and center content defined is as follows
<div class="header_content">
<div id="left">
<ui:include src="navigationMenu.xhtml" />
</div>
<div id="center_content">
<!-- think this panelGroup wrapper can be -->
<!-- removed. need to test that though -->
<h:panelGroup id="centerContentDiv" layout="block">
<ui:insert name="center_content" />
</h:panelGroup>
</div>
</div>

Resources