I have two grids, and one tabView which contains 2 tabs, for first tab I have to show panelgrid1, and for tab2 = panelgrid2. I have used rendered attribute for both panels, and used tabchange event in tabView, this listener updates the status attribute in java, but in xhtml, same grid is still shown and doesn't change 2nd panelgrid.
You need to make absolutely sure that you refer in ajax update/render a component which is always rendered. It is not possible to refer a component which is by itself conditionally rendered in order to show/hide it.
<p:ajax ... update="foo" />
...
<h:panelGroup id="foo">
<h:panelGrid ... rendered="#{bean.grid == 1}">
...
</h:panelGrid>
<h:panelGrid ... rendered="#{bean.grid == 2}">
...
</h:panelGrid>
</h:panelGroup>
See also:
Why do I need to nest a component with rendered="#{some}" in another component when I want to ajax-update it?
Related
I want to apply style to my validation messages because as of right now they are by default red and apply themselves on the bottom left of the page. For instance when a user types in an empty username field, the message "username is required" appears, but it has a bullet before it and it and is red. I also have custom validators on some of my input fields.
<h:panelGrid class="grid" columns="2" id="regPanel">
<h:form>
<h:outputLabel class="outputLabel" value="Username"/>
<h:inputText class="inputText" id="userNameInputText"
value="#{regBean.userName}" required="true"
requiredMessage="Username is required" >
</h:inputText> .... more form inputs with required fields
</h:form>
</h:panelGrid>
First of all, you have to put h:messages or h:message tags in your view where you want to have the messages rendered. With h:messages, all the message of the page are rendered in a central list. With h:message you can just render the messages connected to one component like this:
<h:inputText id="long" value="#{bean.longValue}"/>
<h:message for="long"/>
The styling can be changed with various attributes on h:messages and h:message. There are attributes to set the style directly or a style class for each message severity (info, warn, error, fatal). The style can be set like this:
<h:message for="long" warnStyle="color: green" infoStyle="color: blue"
errorClass="errorMsg" fatalClass="fatalMsg"/>
There is not standard way for "re-use" of the style classes. You would have to put them on each tag without modifications. But there are several ways this could be achieved:
Build a composite component for messages with default styling
Replace the renderer of the message component to support default styles
Use a component library like PrimeFaces
You can use message, growl of Primefaces. and you can get css class of validation message and override it.
For example: i changed css of growl message:
<style type="text/css">
.ui-growl-image.ui-growl-image-error{
background-image: none !important;
background-color: navy;
}
</style>
Demo:http://www.primefaces.org/showcase/ui/messages.jsf
If you use default message of JSF, you must add css class to each component or create your own component.
I need advise with selection listeners in p:dataTable. My view is primefaces extension layout
(pe:layout), with north, left and center section. North section is table and left is a menu.
The idea is that left menu provides a different view for the data in selected table row
and therefore, if the row changes, the whole view need to refresh. (Depending on the view selected in left menu - these are backed by beans backigOne, two and three and only one at the time is active).
So I decided to use multiple rowSelect events for the table, for every bean:
<p:dataTable id="" var="wo" value="#{TableBacking.dataList}"
selection="#{TableBacking.selectedItem}" selectionMode="single" rowKey="#{wo}">
<p:ajax event="rowSelect" listener="#{backingOne.tableChangeListnener}"
update="..." disabled="#{leftMenuBacking.selection != "ONE" />
<p:ajax event="rowSelect" listener="#{backingTwo.tableChangeListnener}"
update="..." disabled="#{leftMenuBacking.selection != "TWO"/>
<p:ajax event="rowSelect" listener="#{backingThree.tableChangeListnener}"
update="..." disabled="#{leftMenuBacking.selection != "THREE" />
...
</p:dataTable>
This works well and since always one item is selected in leftMenuBacking, only one ajax event will be enabled at the time.
The problem is, however, all the backingOne, backingTwo and backingThree beans gets always initialized, because of the declaration:
listener="#{backingXXX.tableChangeListnener}"
and in my case, initialization is costly :( (timewise)
I need a hint of better desing, so the functionality is the same, but only the backing bean of the menu which is curently selected (or enabled as in sense of disabled="#{leftMenuBacking.selection != "ONE") gets initialized and no other does?
Thanks a lot.
EDIT 1 based on Magnus Tengdahl comment:
There are different pages for every selection in leftmenu.
The page backingOne.xhtml looks something like this:
<ui:composition template="/publicResources/templates/gdfoxTemplate.xhtml">
<ui:define name="title">GDFox | Similar Problems</ui:define>
<!-- North contains the section with table that produces rowSelect event as described above -->
<ui:define name="north">
<ui:include src="currentWorkload.xhtml" />
</ui:define>
<!-- Contains the left munu, uses p:menu widget-->
<ui:define name="west">
<ui:include src="leftmenu.xhtml" />
</ui:define>
<!-- center view based on BackingOne bean-->
<ui:define name="center">
....
</ui:define>
</ui:composition>
So basically, every selection on left menu is on different URL (let's just call them backinOne/Two/Three.xhtml. They share all share north and west sections and defines unique center
This is why needed to use three for that table - in order to propage the change to all possible views (althought only one will be selected in time). I dont thing (== I am still failing to see) Magnus that one listenere would solve my problem. If you are sure your idea will work, could you please explain it little bit further?
I would go with having just one rowSelect listener, without any disabled conditions:
<p:ajax event="rowSelect" listener="#{backingOne.tableChangeListnener}"
update="menuArea" />
Then let the backing bean decide what should be done given the selected row. Have a look at the PrimeFaces ShowCase for an example on how to get the selected row in the backing bean. From that information the backing bean surely must know what to do. Basically, you could just call the appropriate backing bean implementation in one of the backing beans.
You haven't given us any code for the left view, but I would recommend something like (if you don't do already):
<h:panelGroup id="menuArea">
<ui:fragment rendered="#{leftMenuBacking.selection == 'ONE'}">
... code for selection "ONE" ...
</ui:fragment>
<ui:fragment rendered="#{leftMenuBacking.selection == 'TWO'}">
... code for selection "TWO" ...
</ui:fragment>
<ui:fragment rendered="#{leftMenuBacking.selection == 'THREE'}">
... code for selection "THREE" ...
</ui:fragment>
</h:panelGroup>
In this way, your left area will be re-rendered (i.e. updated) for every rowSelect and your selection table is left as it is.
I think you could make an extra bean backingbean0. In that bean you have the listener tableChangeListener. As Magnus stated you have 1 p:ajax
And in the tableChangeListener you can call backingbean1 2 or 3 depending on the one that is needed. (you have this info in your backingbean0)
protected Object getBean(String name) {
FacesContext fcontext = FacesContext.getCurrentInstance();
ELResolver resolver = fcontext.getApplication().getELResolver();
Object bean = resolver.getValue(fcontext.getELContext(), null, name);
if (bean == null) {
getLog().warn("An object with name=" + name + " could not be resolved with ELResolver");
}
return bean;
}
and you call it like this
BackingBean1 bb1 = (BackingBean1) getBean("bb1");
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
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?
My goal is to dynamically load the contents of a component in JSF 2.0. The use case is this: user clicks some button, which opens a modal panel with some heavy-contents via AJAX. Due to its' heaviness, I want to delay loading it until/if user actually needs it. If the user closes this panel, it is not actually removed from DOM, just faded out. If the user clicks the initialization button again, the previously loaded panel is shown.
I know that I can prevent rendering of contents using rendered="#{cc.attrs.visibilityState == 'hidden'}" and that I can re-render the component via JSF AJAX call. However, how can I adjust the attributes of a composite component on-the-fly so that the second time around the component would actually render?
1) I know that I could do:
<h:outputLink>Foo
<f:ajax event="click" render="theComponentIWantToUpdate" listener="#{someBean.someMethod()}" />
</h:outputLink>
And then programmatically adjust theComponentIWantToUpdate attributes (to change value of #{cc.attrs.visibilityState}) so that it would actually render with full contents. But how to actually do that?
2) Also, the problem is that I don't want to update (re-render) theComponentIWantToUpdate each time the button is pressed, only the first time (see the business case). How can I set an evaluation for <f:ajax /> call for this? It has the disabled attribute, but it only orders whether or not to actually render the AJAX-handler (not evaluated each time the link is pressed).
3) Furthermore, I probably want to do some custom javascript first when the link is clicked and only execute AJAX request via javascript using jsf.ajax.request(). However, that function doesn't support providing listener attribute so I don't how to execute a backing bean method with raw javascript jsf.ajax.request() call? There is actually a similar question without suitable answers (see JSF 2.0 AJAX: jsf.ajax.request to call method not only rerender an area of page).
A partial solution:
Here is my link that sends an AJAX-request (inside a composite component):
<h:form>
<h:outputLink styleClass="modlet-icon">
<f:ajax event="click" render=":#{cc.clientId}:modalWindow:root" listener="#{modalWindowBean.enableContentRendering(cc.clientId, 'modalWindow')}" />
</h:outputLink>
</h:form>
The listener calls this method:
public class ModalWindowBean {
...
public void enableContentRendering(String clientId, String windowId) {
UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId + ":" + windowId);
component.getAttributes().put("contentRenderingEnabled", true);
}
}
Here is my target to be rendered:
<modalWindow:modalWindow id="modalWindow">
<quickMenu:quickMenuOverlay id="quickMenuOverlay" />
</modalWindow:modalWindow>
ModalWindow simply wraps the target into a nice looking window panel. Within ModalWindow:
<composite:implementation>
<h:outputScript library="component/modalWindow" name="modalWindow.js" target="head" />
<h:outputStylesheet library="component/modalWindow" name="ModalWindow.css" />
<h:panelGroup id="root" layout="block" styleClass="modalWindow hide">
<ui:fragment rendered="#{cc.attrs.contentRenderingEnabled}">
...all the wrapping elements with <composite:insertChildren /> within it
<script type="text/javascript">
// Fade it in
var win = ModalWindow.getInstance('#{cc.clientId}'); // this gets the instance, available everywhere
win.position(#{cc.attrs.left}, #{cc.attrs.top});
win.resize(#{cc.attrs.width}, #{cc.attrs.height});
win.fadeIn();
</script>
</ui:fragment>
</h:panelGroup>
<ui:fragment rendered="#{!cc.attrs.contentRenderingEnabled}">
<script type="text/javascript">
// Initialize modalWindow when it is rendered for the first time
var win = new ModalWindow('#{cc.clientId}'); // will be publicly available through ModalWindow static methods
</script>
</ui:fragment>
</composite:implementation>
The problem? AJAX-request is sent each time user clicks the button (so the window is reloaded and faded in each time). I need to be able to control when/if the AJAX-request is actually sent.
All this stuff makes me miss Apache Wicket, although I'm not sure how I would do this with it anyway :)