I'm new to JSF and I'd like your suggestions on how to implement what I need the best way possible. Also first post in StackOverflow, so please excuse me if I'm not clear about something.
I've a p:tabView with a dynamic amount of tabs, generated with c:foreach in the following way, with a view scoped backing bean.
<p:tabView id="tabViewId">
<c:forEach items="#{controller.list}" var="aTab">
<p:tab title="#{aTab.label}">
<ui:include src="#{aTab.firstUrl}"/>
</p:tab>
</c:forEach>
</p:tabView>
This works and I'm happy with it. Now the thing is each of my tabs have two possible views, and when a certain event is fired (a p:commandLink is clicked in one of the views) I'd like to change what is shown in the tab to the other view that tab has; in other words, I'd like to change the src view that is loaded inside the tab with ui:include. I've tried to return my desired view path in the method associated to this commandLink in the controller, but as expected it redirects to a new page instead of loading it inside the tab.
I'd like to keep the same controller instance when switching the tab contents (my controller is view scoped), and avoid binding.
I've came with two options.
First would be trying something similar to this (obtained from primefaces tabView different tab content with dynamic tabs), getting the view paths from my "aTab" instead of hardcoding them, and then trying to update the tab or the whole tabView on my commandLink after changing the boolean that switches between the two pages in the controller:
<ui:include
src="#{curSearch.closeable ? '/sections/search/searchInstanceTab.xhtml' : '/sections/search/firstSearchTab.xhtml'}">
</ui:include>
The second one would be including both pages in every tab, but rendering only one using the boolean in the controller. This sounds much worse to me than the first option (it's suggested as an answer in the question I linked before).
Thanks in advance, please feel free to suggest any easier/better way.
::: EDIT :::
Finally did choose to have each tab in a separate xhtml file (being loaded with the c:foreach loop) and in each xhtml/tab all the possible views (also in separate xhtmls) ui:include'd with a rendered clause, hardcoded.
Pretty smooth solution and works great, which possibly would allow to have dynamic contents inside each tab, with another c:foreach loop inside them and a list of pairs in the backing bean which would contain the xhtml names and booleans for rendering (that'd become a bit crazy).
The first option, the view build time conditional one, can lead to problems in some cases. E.g. you won't be able to rely on f:param in the conditional expression.
This sounds much worse to me than the first option
It's not much worse. Creating a bunch of components is not that pricey.
It's not a black and white thing, but my general advice would be to not optimize unless you actually have a performance problem and profiling confirmed that this is the bottleneck (unlikely). Stick to the easiest path, which is using rendered.
For Mojarra you can configure logging like this:
<logger category="javax.enterprise.resource.webcontainer.jsf.timing">
<level name="DEBUG"/>
</logger>
And then you'll see exactly how much time building the view (the Restore View JSF lifecycle phase) takes compared to your logic and rendering (the other phases):
19:47:57,026 DEBUG [timing] (default task-3) [TIMING] - [7ms] :
Execution time for phase (including any PhaseListeners) ->
RESTORE_VIEW 1
...
19:47:57,198 DEBUG [timing] (default task-3)
[TIMING] - [172ms] : Execution time for phase (including any
PhaseListeners) -> RENDER_RESPONSE 6
Related
I am working on a JSF application which is supposed to support a big scale of users logged in at the same time. And when we tried with our stress testing, we have observed that a large portion of CPU time is spent on rebuilding and traversing through the component tree.
My first thought was to try to make specific parts of the page stateless and thus be excluded from the component tree. But if I wrap a form element with the f:view being marked as transient:
<f:view transient="true">
<h:form>
....
</h:form>
</f:view>
, all my other forms on the page are also stateless (the hidden input field that is supposed to hold the state has for 'value' attribute value 'stateless': ).
Is there a way to make only specific forms on the page stateless, or the whole page can be either stateless or stateful?
Thanks for any kind of help!
EDIT:
For implementation we are using Mojarra 2.2.7, along with Primefaces 4.0 as a component library and Omnifaces 1.7 for some utility functionalities.
Based on what Balusc has said on this link, applying the transient on a view tag will make the entire view (i.e page) stateless which makes sense because setting transient to true calls the setTransient() on the UIViewRoot object. This can not be accomplished with your current setup. I'm not sure if there is a hack or work around to achieve a single page with multiple states some alternative way.
I have a problem I can't quite get a handle on.
First the context: I am developing a web application using Primefaces 3.5 (yes, unfortunately I am stuck with this old version for now), running on JBoss 7.
There is a form with id "form" encompassing all following xhtml code.
I have a component in my view which is provided by usage of the binding attribute:
<p:dashboard id="dashboard" binding="#{myBackingBean.dashboard}" />
Then sometimes I would like to perform an ajax update on this component, this is done by using the RemoteCommand component of primefaces:
<p:remoteCommand
actionListener="#{myBackingBean.someActionListener()}"
process="#this" id="myRmtCmd" oncomplete="myJsFunction();"
update=":form:dashboard" name="myRemoteCommand" />
The RemoteCommand is triggered by a clicking on a Link:
Some Text
This works pretty well so far. However after deploying this code to production I sometimes get a FacesException:
javax.faces.FacesException: Cannot find component with identifier ":form:dashboard"
referenced from "form:myRmtCmd".
This is where my problem lies because I cannot reliably reproduce this exception. My question is this: What could lead to this exception being thrown? It seems to work 95 % of the time but being the perfectionist I am (and many of you reading this are as well, I'm sure ;) ) I would like this code to work 100 % of the time. What am I missing?
Before answering please consider these constraints:
yes, i have to use the binding attribute for providing the dashboard as I need a great deal of control over what gets added to the component
to avoid using IDs I also tried updating the dashboard by its css class via one of primefaces' advanced selectors: #(.ui-dashboard) - this also does not work!
yes, it would be possible to use a commandbutton/link instead of wiring up the remotecommand component to a simple html link but in this case the link is rendered by a JSF renderer component and I made some bad experiences with dynamically adding buttons etc (due to JSF Spec Issue 790)
Cheers,
p.s.
I also had this weird behavior.
There are probably more than one component bindded to #{myBackingBean.dashboard}, so the first one sets the id and there will be no one called "dashboard".
Is it possible to set current displayed tab programmatically in <p:wizard>?
For example, I want that for two different request to the same page which contains a wizard, to have a different tab selected.
What I am currently trying to do, is to have a wizard with many tabs, in the second tab I have a redirection to another page, so when I come back I want to come to the last step which caused the redirection.
Can you please help me ? Thank you a lot !
According to primefaces documentation there's a step attribute for p:wizard tag, which specifies the step of the wizard you're currently in.
attribute: step
default value: 0
type: String
description: Id of the current step in flow
You must bind this attribute to a value of your backing bean and maintain it during redirection and coming back. If your wizard's bean is #ViewScoped you'll loose that info during redirection step, so you have to pass it using a view param or flash scope.
My answer would most probably not meet your complete requirements, but, nonetheless, it may point you towards solution to your problem.
As far as I know, the PrimeFaces Wizard UIComponent is designed for a workflow of one page. That effectively means that inputs will be handled by a backing beans that is in a view scope.
This way, making a redirection on a certain step will clear all data inputs, because your view changes and the old one is destroyed.
Anyway, a means of setting a current tab for display is step attribute of Wizard component. So,
<p:wizard step="#{wizardBean.currentStep}" >...</p:wizard>
will force the wizard to show you step which you specified in your bean. You may be able to get it by using, for example, a view parameter, like in
<f:viewParam name="step" value="#{wizardBean.currentStep}" />
But it will make sense if lifetime of your bean is more that for a view, for example, the bean could be put in session scope.
That said, maybe it is a better idea to do login beforehand. Or, if it is absolutely necessary to do it in step 2 of your wizard, provide for a built-in login functionality in a page itself, or in a popular window?
Also, programmatically the setting you speak of can be achieved via a binding of component to your backing bean and setting the step value in the backing bean, for example, in a preRenderView event.
I have an ArrayList in a backing bean and his rendering in JSF page with c:forEach. When iI remove the ArrayList element by index, jsf, no matter what index is, always removes the last element. Why happening this?
Remove button in JSF is :
<a4j:commandButton immediate="true" action="#{bean.removeEntry}" ...
So i use immediate attribute. I think problem is because immediate skips Apply request phase in JSF Life Cycle. Is possible?
If yes, than how run Apply request phase in this case ?
Are you using Facelets (.xhtml pages)? If so, you may be running into some common misconceptions about JSTL tags like <c:foreach>. Here's a good article on it:
https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat
Basically, <c:foreach> is processed only when the view is initially built; it does not become part of the component tree, and can have some behavior you don't expect when the backing collection is changed. You may be better off using <ui:repeat> instead.
little more code would have helped, but immediate on command button is basically used for navigating away from current page as actionlistener or action will execute in apply request phase, typical case cancel button. This means you will not get updated value there.
If your logic depends on some other uiinput make that immediate and you can hook things in valuechangelistener.
But I doubt what you are trying to achieve can be done in better way, have a look at this link # SO
I was having the similar issue. I was using 'tr:iterator' to iterate over ArrayList'<'Customer'>'(); 'ui:repeat' solved my problem.
Thanks.
The scenario is like this. I have a rich:tabPanel with about 5 tabs. On first tab there is a rich:datatable. When I click on first column's element (a4j:commandLink), I get another rich:datatable. When I click on first column's element (a4j:commandLink) of this table, I change the tab where I have another rich:datatable and the same thing follows as above. The constraints from previous tab is used to get elements for the current one. If I click on the tab directly I get all elements related to that tab. Each rich:datatable refers to different tables. Each table is interrelated. Each tab refers to a single managed bean. I am using hibernate in backend.
The problem starts now. I dont want the managed beans to be session or application based since there are many variables to store. If I give request scope, the following thing happens. The first table in the tab renders perfectly, however when I click on the first column, the second table doesn't use all constraints since the scope is request, for example actionlistener. What am I supposed to do ?
One thing I can do is define one managed bean for each table. Or forcefully use session scope. Or is there any other way? Please help.
Thanks.
If you are using Richfaces 3.0.0 or above you can annotate your bean with #KeepAlive
or use the tag <a4j:keepAlive beanName="#{bean}" /> instead.
This is an equivalent to the view scope in JSF 2.0.
If you're already on JSF 2.0, use view scope. It's a scope which lives as long as you're interacting with the same page (independently of the browser tab/session!).
If you're still on JSF 1.x, use request scope with an <a4j:keepAlive beanName="#{bean}" /> declared in the view. It behaves like the JSF 2.0 view scope.