I've been facing some problems using JSF with AJAX to render a table without reloading the whole page every time I submit a form.
When I first run the server, my database is empty, so the page is supposed to show only a form to add books. When user submits the form, a fieldset
whith all books is supposed to be rendered. I don't want this fieldset
to be shown when database is empty.
This is a simple version of my code (it is just a small form and a table to be refreshed using AJAX):
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head />
<h:body>
<h:graphicImage library="img" name="caelum-logo.png"/>
<h:form>
<p>Book Title:</p>
<h:inputText id="title" value="#{livroBean.livro.titulo}" />
<h:commandButton value="Add book" action="#{livroBean.addFirstBook}">
<f:ajax execute="@form" render="title :addedBooksTable" />
</h:commandButton>
</h:form>
<div id="addedBooksTable">
<p:fieldset rendered="#{livroBean.numberOfBooks > 0}">
<h:dataTable value="#{livroBean.allBooks}" var="book">
<h:column>
<h:outputText value="#{book.titulo}" />
</h:column>
</h:dataTable>
</p:fieldset>
</div>
</h:body>
</html>
And i wanna focus on this part:
<h:commandButton value="Add book" action="#{livroBean.addFirstBook}">
<f:ajax execute="@form" render="title :addedBooksTable" />
</h:commandButton>
The fieldset and the table inside it are supposed to be hidden when there's no book added to the database, that's why i used <p:fieldset rendered="#{livroBean.numberOfBooks > 0}">
. But I want it to be rendered after I click the commandButton
, even if there's nothing at the inputText
.
Here's what's happening when I test the code:
- if I test the code just as it is with an empty database, the
inputText
is refreshed (it "erases" what were typed before the submisssion) when I click on thecommandButton
, but the fieldset is not. I know that the fieldset has arendered="#{livroBean.numberOfBooks > 0}"
and the inputText does not, but the methodgetNumberOfBooks
is called everytime i click the commandButton, that's why I don't get it... - if I change the
f:ajax
tag so it ends up like this<f:ajax execute="@form" onevent="click" render="title :addedBooksTable" />
, it solves the problem, but i can realize the screen flashing for a while when I click thecommandButton
. As far as I know, one of the uses of AJAX is that we don't want the screen flashing when a request is made.
Why is the fieldset
rendered only when I use onevent="click"
? Should I consider the flashing something normal? Is there a more elegant solution for that?
Thanks!
You can't ajax-update a plain HTML element. You can only ajax-update a JSF component. Simple reason is that the target must be resolveable by
UIViewRoot#findComponent()
, so that JSF can find it in the component tree and render the updated HTML into the Ajax response.Replace
by
Normally, this should have thrown an exception as described in How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar", but they removed this check in Mojarra 2.2.5 in order to support ajax-updating a specific iteration of
<ui:repeat>
and<h:dataTable>
(this missing check will be fixed later on as that's indeed unhelpful to starters like you).As to why adding
onevent="click"
appear to work, that's because it caused a JavaScript error which in turn caused the whole JavaScript/Ajax thing to break down, which in turn caused that the command button fall backs to default synchronous behavior with a full page reload (as if you aren't using<f:ajax>
at all). You likely meant to useevent="click"
instead. Theonevent
attribute serves a different purpose. See also a.o. Proccess onclick function after ajax call <f:ajax>.