Lazy loading parts of seam pages? - ajax

I'm working on a seam application (2.1.1.GA under JBoss AS 4.2.2) where a particular has a number of (sometimes large) sections that do not need to be rendered untill the user interacts with that particular section, think along the lines of an article title where the user clicks on the title and it expands to show a box containing the text.
I can implement this without any problems with Seam and Richfaces but the contents of all the sections are downloaded to the browser when the user first loads the page. Is there anyway for these sections (which may or may not contain richfaces controls themselves) to be downloaded on demand using ajax?
Thanks.

Lots of ways.
Just set rendered="false" on the box and then reRender it's parent container when you click the title.
eg. Where you have a boolean called showContent in your backing Bean that is toggled by the toggleContent() method:
<a4j:commandLink
value="This is a title"
ajaxSingle="true"
reRender="contentDiv"
action="#{someBackingBean.toggleContent}"/>
<a4j:outputPanel id="contentDiv">
<a4j:outputPanel rendered="#{someBackingBean.showContent}">
This is some text that is not rendered when the page loads
</a4j:outputPanel>
</a4j:outputPanel>
EDIT: In response to comment. Another way to do it would be to use the a4j:jsFunction (very handy) and some javascript.
<h1 onclick="toggleContent(this);">This is a title</h1>
<a4j:outputPanel id="contentDiv">
<a4j:outputPanel rendered="#{someBackingBean.showContent}">
This is some text that is not rendered when the page loads
</a4j:outputPanel>
</a4j:outputPanel>
<script>
function toggleContent(element) {
//check if the contentDiv has any contents (maybe check if element has a child under contentDiv)
//if it doesn't then call a4j:jsFunction to load the contentDiv eg. loadContent();
//hide or show div depending on the current state of it
}
</script>
<a4j:jsFunction name="loadContent" action="#{someBackingBean.toggleContent}" reRender="contentDiv"/>
Something like this anyway.

What about if you using scrollable table. How to implement fetching data in chunks?
Ragards
Marko

Related

In JSF on an ajax call, how do we create a HTML fragment using a different JSF page for rendering?

I have a JSF page in which I have a div which acts as a popup window.
This popup is displayed when the user clicks on a certain button or link, until which it is hidden.
I would like to have another JSF page that provides the content for this div via an AJAX call.
I vaguely remember doing this using Struts Action and JSP fragment.
Is it possible to do this in JSF 2.0?
ADDITIONAL DETAILS:
My scenario is as follows:
I have a page that displays the details of employees as a summary table using the dataTable tag with a class EmployeeInfo as a backing bean that provides a Collection of EmployeeBeans. On this page I have a radio button as the first column in the dataTable. This page has a div that is hidden.
When the radio button is switch on and a certain button is clicked, over an AJAX call we need to hit the backing bean to get the details of the EmployeeBean that has been selected as above and populate the div based on this AJAX call.
The reason why I do not want to have a full submit on the first page and get the second page is, because I want to save the state of any changes that have been done on the first page.
Using a tag, you are able to show or hide content quite easily. This is all rough code typed out quickly but in your bean, imagine you had the following:
public class MyBean {
public boolean renderHidden = false;
public void toggleHidden(AjaxBehaviorEvent event) {
renderHidden = !renderHidden;
}
}
Then in your JSF page, you'd have a link to show hide your popup done as a ui:fragment:
<h:commandLink value="Click Me!">
<f:ajax event="click" listener="#{myBean.toggleHidden}" render="hiddenarea" />
</h:commandLink>
<ui:fragment id="hiddenarea" rendered="#{myBean.renderHidden}">
<div><!-- Content to show/hide here --></div>
</ui:fragment>
That ui:fragment could easily be in another JSF page that you include via ui:include if you need it to be. The important bit is that the f:ajax take is what makes the AJAX call (on a click event in this case) and updates the specified element (hiddenarea).

Partial rendering redundant method call

I am aware that JSF may call a managed bean method a couple of times even if it is called only once in .xhtml. I understand that is due to encode* methods.
I would like to ask you to explain the following case to me.
I have a JSF file that sort of looks like this:
<h:form id="form1">
<h:panelGroup id="output">
...
<h:commandLink...>
<f:ajax render=":form1:output"/>
</h:commandLink>
</h:panelGroup>
</h:form>
All clear so far; pressing the command link rerenders a part of the page within the form panelGroup.
The code follows:
<ui:repeat value="#{movieBean.categories}" var="category">
<li>
<h:outputLink value="index.xhtml">
<f:param name="categoryId" value="#{category.categoryId}"/>
<h:outputText value="#{category.description}"/>
</h:outputLink>
</li>
</ui:repeat>
#{movieBean.categories} //this is just a 'test line'
movieBean is request scoped.
Now, when I enter the page for the first time I get two calls to movieBean.categories.
That is clear because it is called twice in the code. However, when I hit the AJAX link rendering
only a part of the page (output) I get movieBean.categories from <ui:repeat> called again even
though it is outside the partially rendered page area. The 'test line' is not called this time.
I performed another test. I deleted the <ui:repeat> tag leaving the 'test line' only.
AJAX partial rendering dosen't call it as before.
What makes the movieBean.categories call inside a <ui:repeat> tag different
than the one in 'test line'? And why is the call inside <ui:repeat> made when pressing the AJAX link
even though it is outside partially rendered <h:panelGroup id="output"/> tag?
I'm pretty sure that "redundant" call is made within a phase where JSF rebuilds element tree to store POST data into appropriate elements.
So you basically have two getter calls per request if you stay on the page. First one to store new form values, then to render page content.

Primefaces Change menu entry via ajax an rerender content on full layout

I am trying to get a simple full layout to work with a navigation on the left side.
That works but I want to reload the center (content) via ajax on menu item selection.
The reason is, that I have a MP3 player on the right side and if the whole page reloads the mp3 player
start the playback again.
On Richfaces I did that with a session bean which holds the actual filename that needs to be rendered in the center
and on menu click the action method analyses the menu entry ID and sets the filename to its corresponding.
Actually that works a little bit for primefaces as well, but the content doesn't render correctly. After punshing F5
it is perfect.
Does anybody can give me a real simple example how I can do that?
Many greetings,
Hauke
I have never use menuitem but with commandButton I just use 'update' notation to refresh the form located in the center content via ajax.
On navigation layoutUnit
<p:commandButton
value="Enter"
image="ui-icon ui-icon-comment"
update="form_input_console form_output_console:tabbed_contents"
actionListener="#{dashboardUi.processCommand}" />
and on the center layout unit
<p:layoutUnit position="center">
<h:form id="form_output_console">
<p:tabView
id="tabbed_contents"
dynamic="true">

p:commandButton update doesn't work in ui:include

I want to update a part of a page by PPR.
This is the part of page that i want to update:
<h:panelGroup id="aggiungiAuto"
rendered="#{!autoBean.operazioneOk}">
<ui:include src="../component/aggiungi_auto.xhtml"/>
</h:panelGroup>
While this is the commandButton present in aggiungi_auto.xhtml
<p:commandButton value="Submit"
update="growl aggiungiAuto aggiungiFoto"
actionListener="#{autoBean.insert}"/>
Any Idea?
JS/Ajax works on the client side, not on the server side. JSF works on the server side, not on the client side. When you instruct JSF to not render the component to HTML, then nothing will be present in the client side, so JS/Ajax will be unable to locate the HTML element to refresh/update.
You need to wrap it in another <h:panelGroup>.
<h:panelGroup id="aggiungiAuto">
<h:panelGroup rendered="#{!autoBean.operazioneOk}">
<ui:include src="../component/aggiungi_auto.xhtml"/>
</h:panelGroup>
</h:panelGroup>
This way the <span id="aggiuniAuto"> is always present in the client side, so JS/Ajax will be able to update it with the new HTML data generated by JSF.
So I was having this kind of a problem with PrimeFaces (the above answer not being sufficient this time), and I also discovered a solution.
Part of the problem I think was that I was using ui:include recursively. For whatever reason, PrimeFaces was irrationally causing UI components to be bound to the backend data out-of-sync; e.g., when an "Add" button was clicked, a new value would be created in the UI, but then the data for it would be ripped out of the values for the section below, etc...
The explanation? "[O]n a viewscoped bean, a hidden field is added to the form to hold post-back data[;] if that field is not included with the process, then the bean will lose context." This particular problem is prevalent with ui:include recursion especially. Solution (all regarding the p:commandButton or other actionable component):
Ensure that update and process are pointing to a JSF component, not a regular HTML component.
update the next scope up if it breaks (goes out-of-sync with the binding).
Use styleClass's for update (not e.g. PF ID's or #this:#parent kind of stuff), so that jQuery is utilized instead of PF, e.g.: #(.fieldset-class).
process whatever scope is being updated. (This is needed for the post-back data so that the Bean keeps its context for the update...) process="#this" is not needed here, provided that the button is contained by the process value component.
For all buttons without validation wanted, set immediate="true".
If none of the above works (which happened with the Add buttons, probably due to ui:include recursion), set process="#this", immediate="true", and update="#none", and then oncomplete="remoteCommandName();", and have a p:remoteCommand instead with that name with the process, immediate, and update mentioned in the above points.
If none of the above works (which happened with some other buttons, probably due to being yet another layer deeper in the ui:include recursion)... wrap a h:panelGroup around the next c:forEach up and then update the PrimeFaces ID of that in the button itself while keeping its remoteCommand call afterwards, as specified above.
If none of the above works (which happened yet again to me)... Try the following code:
In the p:commandButton(s): oncomplete="$('.FixButtonSC').click();"
In the p:fieldset with a style class of FieldsetSC:
<!-- Fix (hidden) button. -->
<p:commandButton id="FixButton" styleClass="FixButtonSC"
process="#this" update="#(.FieldsetSC)" style="display: none;" />
Hope that helps...

RichFaces: Displaying a notification "popup" when AJAX operation succeeded

We are currently developing a B2B web shop based on Java EE 5, JSF, Facelets and RichFaces. The technology has really worked very well so far, but now I am facing a small problem I just can't figure out how to solve:
Products are listed as tables, where every item can be added to the shopping basket by clicking on a small icon at the end of the row. Adding the product is done via AJAX to avoid the full reload of the page. This works without any problems just by using a h:dataTable and an a4j:commandLink to call an action-method which adds the selected product to the basket. Even the re-rendering of the basket total always visible in the side-bar is working properly.
Due to the nature of AJAX, there is no visible indication (except the changing total at the side) that the operation was successful or has been completed at least. Now I want to add a little "popup" box, which is made visible next to the add-icon when the AJAX-operation is completed, stating that the item was added to the basket. This box should automatically go away after a few seconds.
This is what I think should work (the popup_message and popup_content css-classes make the box float above the position where its markup is):
<h:dataTable ....>
...
<h:column>
<a4j:commandLink action="...">
<rich:effect event="oncomplete" targetId="addedMessage"
type="Appear" />
<rich:effect event="oncomplete" targetId="addedMessage"
type="Appear" params="{delay:3.0, duration:1.0}" />
</a4j:commandLink>
<a4j:outputPanel id="addedMessage" styleClass="popup_message"
style="display: none">
<a4j:outputPanel layout="block" styleClass="popup_content">
<h:outputText value="Item added!" />
</a4j:outputPanel>
</a4j:outputPanel>
</h:column>
</h:dataTable>
Unfortunately, it doesn't display the box at all. If I change the event of the "Appear" effect to onclick it works almost as expected. It is immediately shown when the icon is clicked and it dissapears 3 seconds after the AJAX operation was completed. But I don't want it to appear immediately after the click, because it would be wrong to indicate that the item was added to the basket, when in fact the operation hasn't even started yet. This becomes even more important, when I want to indicate some error or want to include some item specific information into the box, which is only available after the item was added.
So any ideas how to do this? And why adding two effects for the same event does not work?
(I've already looked at the effect-example from the RichFaces live demo. The examples do almost work the same, execept that they add the second effect with explicitly stating the for attribute. But even this does not work for me.)
Update: I've tried using the rich:toolTip for this purpose, which actually seems to be quite flexible. But no matter what I do, I can't attach anything to the "oncomplete" (I've also tried just "complete") event of the a4j:commandLink, except one effect... seems there is some bug/undocumented behaviour regarding that event. I've just found this bug report: RF-3427
you can try rich:notify for this
http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=notify&skin=blueSky
Have you tried rich:status ? I will not post a piece of code. I think the docs will do just fine.
http://livedemo.exadel.com/richfaces-demo/richfaces/status.jsf
Your defining targetId outside the parameters. What you want to do is:
<rich:effect event="oncomplete" type="Appear" params="targetId:'addedMessage',delay:3.0, duration:1.0" />
Try that, and I think it will work.

Resources