JSF: UI component dynamic rebinding in a single page wihout reload. Possible? - jsf

Being inspired with the article considering the dynamic table rendering (thank you BalusC), I've finally got the exact result I wanted before here a bit earlier. That gave quite perfect results since I could control the behavior of a every single column respecting the business logic requirements. But that was pretty cool if that table was a part of an experimental "static" page where I was making some dynamic binding experiments.
Once I had to merge the ideas to the existing code (more or less stupid knowing nothing about the dynamic expressions), I've got face to face with the following problem: the dynamic binding seems to work only once during the load of the page. Ok, I thought that I was missing to separate the dynamic binding bean and the "main" page bean (controlling user actions like clicking the tree nodes by a user).
A simplified instance of my current page piece is as follows (consider you have a tree at the left and when you click a tree node, you have to get quite another data table [PrimeFaces used]):
a tree, table selector (works pretty perfect)
<p:tree value="#{tableViewsPageBean.root}" var="node" dynamic="true" cache="false"
selectionMode="single" selection="#{tableViewsPageBean.selectedNode}">
<p:ajax event="select" listener="#{tableViewsPageBean.onNodeSelect}" update=":form:scene"/>
<p:treeNode id="treeNode">
<h:outputText value="#{node}"/>
</p:treeNode>
</p:tree>
a table that's intented to be dynamically rendered once a user clicks a tree node above
<h:panelGroup id="scene">
...
<h:panelGroup binding="#{dynamicDataTableBean.dataTableGroup}"/>
</h:panelGroup>
The tableViewsPageBean is defined as a #ViewScoped bean, and the dynamicDataTableBean is a #RequestScoped bean (I should not think that it might help -- I just had an idea).
But, for me, the following code is requested only once during the page load:
public HtmlPanelGroup getDataTableGroup() { ... }
I don't know, but is it possible to force this code execution to rebind the component in the panel group mentioned above without page reload? Thanks in advance.

Sorry, my bad. I had the following in my web.xml:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
That option must be set to true. However, then I still have the problem described here.

Related

What does <f:facet> do and when should I use it?

I have been having trouble with the tag <f:facet>. I am working form other examples of code which use it, but I'm not sure exactly what purpose it serves.
I have written some code which in method is exactly the same as other code I have seen which works, except there's is wrapped in a <f:facet name=actions> tag. When I add this around my code the drop down box I am wrapping it around disappears when I deploy. Anyone able to suggest a reason for this or give me an insight into how and when to use facet?
Here is my code, I won't bother adding the bean code as they're just basic getters and setters and I don't think they're causing the trouble.
<f:facet name="actions">
<p:selectOneMenu id="SwitchWeekDrpDwnMenu"
value="#{depotWorkloadBean.selectView}"
partialSubmit="true">
<p:ajax update="mainForm"
listener="#{depotWorkloadBean.updateView}" />
<f:selectItem itemLabel="Day view" itemValue="Day"/>
<f:selectItem itemLabel="01/01/2014" itemValue="Week"/>
</p:selectOneMenu>
</f:facet>
If I remove the facet tag the dropdown box displays, but doesn't function as it should with the beans.
A facet represents a named section within a container component. For example, you can create a header and a footer facet for a dataTable component.
https://web.archive.org/web/20170828020413/http://www.jsftoolbox.com/documentation/help/12-TagReference/core/f_facet.html
It's useful when you want to create component that uses some code from user (let's say wrapper).
ie. when you want to create component that hides long text and shows short version of it. You can use just the element body, but then you will get only one value, if you want to get from user the short AND the long version then you can not do it in one value (without using some discriminant), just use facet and say which one is the long and which is the short version.
<textShortener>
<f:facet name="short">
This text is short.
</f:facet>
<f:facet name="long">
This text is too <b>long</b> to be showed when page loads. User have to click the button after the short text to show this.
</f:facet>
</textShortener>
Yes, this can (and should) be done with jsf templating, but I hope you got it.
To question: you defined facet just in the wild xml, nobody requested it so nobody processed it - that's why it did not throw error nor showed anything.

Composite component in ui:repeat vs c:forEach using ajax calls

I have a composite component, which represents an item that will be stored in a list. I would like to display these items using <ui:repeat>, but I have problems making ajax calls. The thing is that for <f:ajax> render attribute, I want to give the id of my component through
#{cc.clientId}
However this raises error when I use it with <ui:repeat>, because of the reasons that are explained in this document https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat.
<cc:implementation>
<div id="#{cc.clientId}">
<h:form>
<h:commandLink styleClass="btn btn-info" value="Click me">
<f:ajax execute="#form"
render=":#{cc.clientId}"/>
</h:commandLink>
</h:form>
</div>
</cc:implementation>
Is there a way to make the above component work using <ui:repeat> (for example is there a component which can replace the <f:ajax> tag handler, or are we stuck to <c:forEach> construct)?
<ui:repeat id="myComponent" value="#{backingBean.myComponentItem}" var="item" varStatus="itemIndex">
<components:exampleComponent id="myComponent"/>
</ui:repeat>
So I start using <c:forEach> instead of <ui:repeat>, and I was able to use the id of my component in the render attribute of <f:ajax>. But this time when I make pagination, if the size of the list decreases I start having empty components in my page. For solving this I started doing pagination through ajax calls and this solved the empty component problem.
Just I thought everything was solved I encountered another problem: lets say I have a page listing 10 components, and I went to another page, and from that page I came to the component displaying page again, but for some reason lets say this time I retrieved only 3 items from database, and I just want to display these 3 items through my components but nothing else.. Unfortunately in this scenario, 3 items are displayed correctly, but the page also contains 7 empty components too. For overcoming this I need to redirect to this page one-more time. So I just gave up at this point. Apart from this I also eventually get the exception below, when the number of the components on the page changes.
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.sun.faces.application.view.StateHolderSaver
I tried using the suggestion explained in the post Jsf Error : java.lang.ClassCastException, but it didn't work for me, I started getting another error which is similar to above exception.
<context-param>
<param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
<param-value>/pagename.xhtml</param-value>
</context-param>
So after these long explanations I would just like to learn what is the best approach for creating composite components which are ajax-enabled, who are fully responsible of their own-states and independent of other components, and that can be displayed in the page more than once and the number of components may vary during the page life-cycle (through pagination, navigation etc).
So far the best solution I came up with is, to check number of components in the page and when that number changes through an ajax call or because of a navigation from another page, redirect to the destination page one more time, this refreshes the empty components in the page without creating much disturbance to users. If you come up with any better solution please let us know.

How to use ui:include inside a forEach and use the loop variable inside the included page?

I'm upgrading to JSF 2.0.2 inside Tomcat 7.0.12 and I have a page with a variable number of reusable widgets on it. I used to use t:aliasBean for this purpose, but it doesn't seem to work. I'm now trying the following in my Xhtml:
<c:forEach items="${viewBean.currentView.parts}" var="part">
<t:div styleClass="div#{viewBean.partNumber[part]}">
<c:forEach items="${part.widgets}" var="widget">
<f:subview id="div#{viewBean.widgetId[widget]}">
<ui:include src="widgets/#{widget.widgetPage}">
<ui:param name="widget" value="#{widget}" />
</ui:include>
</f:subview>
</c:forEach>
</t:div>
</c:forEach>
What seems to happen is the next widget from the loop is used in the previous widget's page, so I get errors unless there is only one widget.
Edit: I've tried ui:repeat - it doesn't work. I've also tried removing the ui:include, just as a sanity test; the looping works fine. Also, I'm using Spring 2.5.6.SEC01 - though it shouldn't matter.
I propose to use ui:repeat instead of c:forEach.
Why?
The most important thing to understand
about the jstl tags in Facelets is
that they do not represent components
and never become a part of the
component tree once the view has been
built. Rather, they are tags which are
actually responsible for building the
tree in the first place. Once they
have done their job they expire, are
no more, cease to be, etc etc.
Source [here][1]. I really recommend to read the entire article.
UPDATE:
Please note that I do not say that c:forEach is bad. I want to underline that mixing it with ui:repeat it's not recommended.
[1]: https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat

How to set value in bean using use c:set with jsf?

I have another problem to solve. I have a code on my xhtml page:
<t:dataList id="myDataList" value="#{myBean.myList}" var="element" first="0" `rows="10" dir="LTR" frame="hsides" rules="all">`
<c:set target="#{myBean}" property="fid" value="#{element[0]}"/>
...
</t:dataList>
The problem is that value of 'fid' in a bean is null when I`m checking it. When I wrote:
<c:set target="#{myBean}" property="fid" value="8"/>
everything works fine and value is set to '8'. How should i fix this? Thanks for replies.
JSTL tags runs during view build time. JSF tags runs during view render time. You can visualize it as follows: JSTL runs from top to bottom first when the JSF component tree is to be populated, then hands over the component tree to JSF and finally JSF runs from top to bottom to render the HTML.
The element[0] is not there when JSTL is creating the view. It's only there when JSF is rendering the HTML. However, 8 is hardcoded and it is always there.
There are several ways to achieve it the proper way, but since the functional requirement is unclear, I can't suggest a proper approach. Maybe you need f:setPropetyActionListener. Maybe you need DataModel#getRowData() or UIData#getRowData(). Or maybe you don't need it at all.

JSF 2.0: Preserving component state across multiple views

The web application I am developing using MyFaces 2.0.3 / PrimeFaces 2.2RC2 is divided into a content and a navigation area. In the navigation area, which is included into multiple pages using templating (i.e. <ui:define>), there are some widgets (e.g. a navigation tree, collapsible panels etc.) of which I want to preserve the component state across views.
For example, let's say I am on the home page. When I navigate to a product details page by clicking on a product in the navigation tree, my Java code triggers a redirect using
navigationHandler.handleNavigation(context, null,
"/detailspage.jsf?faces-redirect=true")
Another way of getting to that details page would be by directly clicking on a product teaser that is shown on the home page. The corresponding <h:link> would lead us to the details page.
In both cases, the expansion state of my navigation tree (a PrimeFaces tree component) and my collapsible panels is lost. I understand this is because the redirect / h:link results in the creation of a new view.
What is the best way of dealing with this? I am already using MyFaces Orchestra in my project along with its conversation scope, but I am not sure if this is of any help here (since I'd have to bind the expansion/collapsed state of the widgets to a backing bean... but as far as I know, this is not possible). Is there a way of telling JSF which component states to propagate to the next view, assuming that the same component exists in that view?
I guess I could need a pointer into the right direction here. Thanks!
Update 1: I just tried binding the panels and the tree to a session-scoped bean, but this seems to have no effect. Also, I guess I would have to bind all child components (if any) manually, so this doesn't seem like the way to go.
Update 2: Binding UI components to non-request scoped beans is not a good idea (see link I posted in a comment below). If there is no easier approach, I might have to proceed as follows:
When a panel is collapsed or the tree is expanded, save the current state in a session-scoped backing bean (!= the UI component itself)
The components' states are stored in a map. The map key is the component's (hopefully) unique, relative ID. I cannot use the whole absolute component path here, since the IDs of the parent naming containers might change if the view changes, assuming these IDs are generated programmatically.
As soon as a new view gets constructed, retrieve the components' states from the map and apply them to the components. For example, in case of the panels, I can set the collapsed attribute to a value retrieved from my session-scoped backing bean.
Update 3: I got it working as described above. To sum it up, the solution is to store the relevant properties in a session-scoped bean instead of making the entire UIComponent session-scoped. Then, when the component is re-constructed after navigation has occurred, set the attribute values by retrieving the saved properties (using EL), e.g.
<p:panel collapsed="#{backingBean.collapsedState}" ... />
(This is a simplified example. Since I am using multiple panels, I am using a map to store these properties, as described above).
One solution would be to use session-scoped beans.
What do you mean by collapsible panels? I ask because there is a component that is closable as well as a component. I am using in the navigation pane in my project. The accordianPanel has an attribute named "activeIndex". Here's what I did in my sessionBean to maintain the state of my accordion tabs:
private int tabIndex; //declared a private variable
public SessionBean() {
tabIndex = 100; //set the initial tab index to 100 so all tabs are closed when page loads.
}
public int getTabIndex(){
return tabIndex;
}
public void setTabIndex(int tabIndex){
this.tabIndex=tabIndex;
}
in my navigation pane:
<p:accordionPanel activeIndex="#{sessionBean.tabIndex}" collapsible="true" autoHeight="false">
<p:tab title="#{tab1_title}">
<h:commandLink value="link here" action="target_page?faces-redirect=true" /><br/>
</p:tab>
<p:tab title="#{tab2_title}">
<h:commandLink value="link here" action="target_page?faces-redirect=true" />
</p:tab>
<p:tab title="#{tab3_title}">
<h:commandLink value="link here" action="target_page?faces-redirect=true" />
</p:tab>
</p:accordionPanel>
I'm not using the tree component for navigation as that presented my project with some difficulties that were easily overcome by using the accordionPanel, so I can't speak to that part of your navigation.

Resources