In my composite component, I have a ui:repeat that has, among other static things, a command button, like this:
<ui:repeat var="article" value="#{cc.attrs.articleList}">
<strong>Aricle: #{article}</strong>
<h:commandButton id="addToFavs" value="Subscribe" binding="..." type="..." >
<f:setPropertyActionListener value="#{article}" target="..." />
</h:commandButton >
</ui:repeat>
Now, I'd like to expose this event in the composite interface, so that in my page, I may attach event listeners and tie in f:ajax.
Had it been outside of ui:repeat (i.e., there existed only one such button), that would have been quite easy, like this:
<composite:interface>
<composite:actionSource name="addToFavs" targets="#{cc.clientId}:addToFavs" />
<composite:clientBehavior name="ajax" default="true"
event="action" targets="#{cc.clientId}:addToFavs"/>
</composite:interface>
But that fails in this case, because there's no one component by that ID (addToFavs), but rather a bunch of them. Do you know how should I expose these buttons in the interface?
Regards,
Pradyumna
Updating this post with my best guess, just in case someone wants to know if I could achieve it:
No I couldn't do it. Looks like we can't do it. We can only expose components whose IDs relative to the composite component are known to the component author apriori.
Related
h:messages component inside a h:form is showing messages related to outside components as well.
How can I restrict it to show messages only related to components inside the containing h:form?
I don't prefer bloating up my code with a separate h:message tag for each & every input component.
Using Primefaces 3.4-SNAPSHOT with JSF 2.2.0-m03
You can make an ajax call to only render the wanted <h:messages.
for example
<h:commandButton value="submit" actionListener="#{fooBean.submit}">
<f:ajax render="msgs"/>
</h:commandButton>
<h:messages id="msgs" globalOnly="true"/>
or in case of primefaces use update attribute in the command button to make the ajax call
Unfortunately, I made a mistake of choosing JSF for an internet facing, high traffic application, now I am wondering as to how to improve the scalability of this JSF webapp.
I have a JSF page that displays a large no of items each of which may be commented upon.
Inorder to reduce the state & improve performance I am trying to reduce the no of forms /commandButtons on the page.
1. Through what ways can I reduce the component tree/ statefulness of JSF ? Do the plain html elements(that are mixed in between the jsf tags) also form part of component tree ? I dont know how component state saving has been helpful to my app since I have been following plain request/response model while designing my app, (may be it is helpful for just JSF's internal requirements)!?
2. I was thinking of an approach where instead of creating a separate <h:form> (each with a separate commandButton) for every item like below,
(Usual Approach)
<h:form> <!-- for each item a separately -->
<h:outputText value="Add comment"/>
<h:inputTextarea value="#{itemController.comment}" required="true"/>
<p:commandButton actionListener="#{itemController.addUserComment(123)}" value="Add" />
</h:form>
(Alternate Approach)
I am trying to make the above better by just putting a single remoteCommand for all the items & pass the required parameters to this remoteCommand.
<form>
<input id="item1_comment"/>
<button onclick="addComment(123, 'item1_comment');"/>
</form>
<script type="text/javascript">
function addComment(itemId, id) {
$('#comment_in').attr('value', $('#'+id).attr('value'));
$('#forItem_in').attr('value', itemId);
addComment_RC(); // call remoteCommand to show the content in dialog
}
</script>
<h:form prependId="false" > <!-- for all items, just single remoteCOmmand -->
<h:inputHidden id="comment_in" value="#{itemController.comment}"/>
<h:inputHidden id="forItem_in" value="#{itemController.forItem}"/>
<p:remoteCommand name="addComment_RC" process="#form" actionListener="#{itemController.addComment()}" />
</h:form>
Is it better to do it this way (or are there any issues with this approach)?
Performance issues in the situation you describe are often caused by the large number of EL expressions, That burdens the server.
One approach to tackle this issue is to compute the comments on the client side, and pass them all at once to the server. Thus reducing the number of comment EL expression to one or none, and use only one button.
Place all the elements in one form. The comments fields are not binded.
<h:form>
// first element
<h:outputText value=#{first element}
// first comment
<h:inputTextarea id="comment1"/> <-- notice there is no EL expression
But we use a unique id for each comment
// second element
<h:outputText value=#{second element}
// second comment
<h:inputTextarea id="comment2"/>
.
.
.
</h:form>
From here you could either
1. after each blur event in any of the comment fields, ajax the server and pass as parameters the comment and the id of the comment from which the ajax call was made. on the server update your model accordingly
Or You can also gather all the comments on the client side and send them to the server at one time.
2. When the user press the submit button call a js function to aggregate all the comments in a structure that you will be able to parse easily on the server side
(ie. "{c1,comment a};{c2,comment b};{c5=,comment e}...").
pass that string to the server, parse it and update your model accordingly.
3. after each blur event in any of the comment fields, call a js function that updates an hidden field.
<h:inputHidden value="{myClass.allComments}" />
when the user submits the form parse allComments and update your model accordingly.
EDIT:
To address the general performance issue I've added recommendations from an article that I found helpful speed up part 1 Speed up part 2.
Hope this helps
btw, I would recommend the first approach rather than the last two.
JFS1.2 + Richfaces 3.3
Situation is as follows:
JSP page renders conditionally one or another panelGroup.
Within each panelGroup there are couple setters and one command button.
Each of two panelGroups uses own bean for setting and performing action.
On the top of a page there's selectOneRadio with (obvious) two items - coresponding tow options of conditional rendering.
Page renders properly, switcher causes to render appropriate panel.
Case is, commands buttons doesn't call an action.
I know what's going on - when I click a button to call action dom is regenerated, but the value that hold my decision to display particular panel doesn't exist anymore. The button is not recreated, action is not fired.
Technically:
<h:selectOneRadio value="#{reportType}">
<f:selectItem itemLabel="x" itemValue="x"/>
<f:selectItem itemLabel="y" itemValue="y"/>
<a4j:support event="onclick" reRender="xPanel, yPanel/>
</h:selectOneRadio>
<h:panelGrid id="xPanel "columns="2" rendered="#{reportType eq 'x'}">
<...some setters>
<... commandbutton>
</h:panelGrid>
<h:panelGrid id="yPanel "columns="2" rendered="#{reportType eq 'y'}">
<...some setters>
<... commandbutton>
</h:panelGrid>
Question is, how to design the page to obtain proper rendering and actions?
For now, I created additional session bean that holds switching value (x|y), but that desing smells bad for me...
RichFaces 3.3 offers the <a4j:keepAlive> tag which does basically the same as Tomahawk's <t:saveState> and JSF2 #ViewScoped. Add the following line somewhere in your view:
<a4j:keepAlive beanName="#{bean}" />
This will keep the bean alive as long as you're returning null or void from action(listener) methods.
See also:
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?
I have a set of jsf components that are statically generated from a set of excel files (they are updated by business people). Each generated file represents a business object that has slightly different data, and all of them belong to a same class.
In order to render this dynamically, the only solution I found was to set up a bunch of ui:fragment and dispatch to the right component at runtime:
<!-- IMPLEMENTATION -->
<composite:implementation>
<ui:fragment rendered="#{cc.attrs.type eq 'cartcred'}">
<limites:limites-cartcred limite="#{cc.attrs.limite}"/>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.type eq 'cdcp'}">
<limites:limites-cdcp limite="#{cc.attrs.limite}"/>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.type eq 'cheqpredatado'}">
<limites:limites-cheqpredatado limite="#{cc.attrs.limite}"/>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.type eq 'confirming'}">
<limites:limites-confirming limite="#{cc.attrs.limite}"/>
</ui:fragment>
<!-- many more lines -->
<!-- many more lines -->
<!-- many more lines -->
<ui:fragment rendered="#{cc.attrs.type eq 'contacorr'}">
<limites:limites-contacorr limite="#{cc.attrs.limite}"/>
</ui:fragment>
But I found out that the perfomance of this is terrible. I tought that JSF would only render a single component, but it seems that it is rendering all of them and "hiding" the others at runtime.
Is there a more efficient way of achieving my goal? I want to render a single component based on runtime information about a business class (much like an if-then-else), but I can only determine what is the component to render at runtime.
Clarification:
what happens is that each component referenced by limites:limites* is a huge complex page with lots of other components. At runtime, the parameter named type' will decide what component to render. But my tests show that if I only render one component, but leave the otherui:fragments` (even knowing that they will not be rendered), it will render much slower than if I remove the components.
So if my page is exactly like this:
<composite:interface>
<composite:attribute name="type" required="true" />
<composite:attribute name="limite" required="true" />
</composite:interface>
<composite:implementation>
<ui:fragment rendered="#{cc.attrs.type eq 'cartcred'}">
<limites:limites-cartcred limite="#{cc.attrs.limite}"/>
</ui:fragment>
</composite:implementation>
it will render much (around 10x) faster than the initial version, even though the parameters are the same. I suspect that JSF will create the entire component tree and only at runtime it will decide (depending on the supplied parameter) if it will render each other or not.
Edit
Almost there. I just need to include my composite component dynamically. I tried evaluating an ELExpression but that didn't work. What I need is a way of accessing the current scope within the component creation, and using that to generate the proper file name:
//obviously, ELExpressions don't work here
Resource resource = application.getResourceHandler().createResource("file-#{varStatus.loop}.xhtml", "components/dynamicfaces");
Yes, the rendered attribute evaluates during render time, not during build time. Yes, it is relatively terrible. Imagine that one such a condition costs 1ms, evaluating ten of them would take in total 10 times longer, 10ms. If you in turn have ten of those components in a paginated table, the webapp loading time would take 0,1 second longer. About one eyeblink longer. But if you don't paginate and/or are using MSIE as reference browser, then it would take much longer. Are you paginating the data and testing in proper browsers?
Best what you could do is to replace the <ui:fragment> by JSTL tags like <c:if>/<c:choose> so that it evaluates during build time, not during render time. Or, alternatively, build the component tree in the backing bean constructor instead of in the view.
One possibility might be to use the binding attribute to access a container
component from inside your managed bean and build the component tree from the
java side. That way you could include only the needed components, unneeded
components won't be evaluated at all.
JSP:
<h:panelGroup binding="#{managedBean.panel}"/>
Managed Bean:
private UIPanel panel;
// getter and setter
// Action method, might also work in a #PostConstruct
public String showComponent() {
if (showComponent1) {
UIOutput component1 = new HtmlOutputText();
component1.setValue("Hello world!");
getPanel().getChildren().add(component1);
}
return "viewId";
}
I haven't used this together with composite components yet, this question seems to have some more details and an example application regarding using this with composite components.
Edit: Regarding your edit, you can also evaluate EL expressions in your managed bean like this:
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory exprFactory = facesContext.getApplication().getExpressionFactory();
ValueExpression expr = exprFactory.createValueExpression(elContext, "#{expr}", String.class);
String value = (String) expr.getValue(elContext);
I'm using facelet templating and I think I'm running into an issue with ui:define and the JSF lifecycle. My template.xhtml contains a fixed menu in the header, simplified it has links like this:
<h:commandLink value="Click Me">
<f:ajax update="#{myBean.listener}" render="contentpanel"/>
</h:commandLink>
The template.xhtml also contains a ui:insert statement:
<ui:insert name="content">
<h:outputLabel value="content placeholder"/>
</ui:insert>
Now I have a content.xhtml which looks like:
<ui:composition template="template.xhtml">
<ui:define name="content">
<h:panelGroup id="contentpanel"/>
</ui:define>
</ui:composition>
So much for the introduction. When I click the commandlink 'Click Me' I'm calling my listener. This listener sets a reference in a backingbean to dynamically load the content based on the link I clicked.
This rendering is not done the first time I press the commandlink. Well it basically looks like it first does the re-render and then call the listener instead of the other way around. So when I first click, nothing seems to happen. When I click for the second time I see the content that was set for the first click. When I click for the third time I see the content of the second click.
I think it's because the ui:define view is already re-built in the 'Restore View' phase of the JSF lifecycle. Any ideas on how to overcome this?
UPDATE
Seems like my assumption was wrong. The cause of this seems to be something different. The #{myBean.listener} has a #SessionScoped #ManagedProperty which is updated after the CommandLink is clicked. The contentpanel actually loads data via the #{myBean.data} which is #RequestScoped. This #{myBean.data} did not reload the data correctly. I solved it by passing the getData() method directly to the #SessionScoped bean.
Might be a bit confusing. But my conclusion: it does work to partial render a component which is loaded via facelet templating (ui:define / ui:insert)
Seems like my assumption was wrong. The cause of this seems to be something different. The #{myBean.listener} has a #SessionScoped #ManagedProperty which is updated after the CommandLink is clicked. The contentpanel actually loads data via the #{myBean.data} which is #RequestScoped. This #{myBean.data} did not reload the data correctly. I solved it by passing the getData() method directly to the #SessionScoped bean.
Might be a bit confusing. But my conclusion: it does work to partial render a component which is loaded via facelet templating (ui:define / ui:insert)