AJAX i JBoss Seam
Często gdy użytkownik wykonuje jakąś operację na formularzu, zmienia się niewielki fragment strony. Jednak z powodu sposobu renderowania dokumentów html, w takiej sytuacji odświeżana jest cała jego zawartość. Stosunkowo niedawno powstał nowy sposób ładowania informacji na stronę – AJAX.
Seam pozwala w prosty sposób używać tego rozwiązania w aplikacjach internetowych, co też zamierzam dzisiaj pokazać. W tym celu posłużę się napisaną uprzednio konwersacją, a właściwie odpowiadającym jej plikiem XHTML:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
template="layout/template.xhtml">
<ui:define name="body">
<rich:panel>
<f:facet name="header">
sampleConversation
</f:facet>
<div class="dialog">
<div class="prop">
<span class="name">Value</span>
<span class="value">
#{SampleConversation.value}
</span>
</div>
</div>
<div style="clear:both"/>
</rich:panel>
<h:form id="SampleConversation">
<div class="actionButtons">
<h:commandButton id="begin" value="Begin"
action="#{SampleConversation.begin}"
rendered="#{not conversation.longRunning}"/>
<h:commandButton id="inc" value="Increment"
action="#{SampleConversation.increment}"
rendered="#{conversation.longRunning}"/>
<h:commandButton id="end" value="End"
action="#{SampleConversation.end}"
rendered="#{conversation.longRunning}"/>
</div>
</h:form>
</ui:define>
</ui:composition>
W tej chwili każdorazowe naciśnięcie przycisku skutkuje przeładowaniem całej zawartości strony. Dlatego też trzeba dodać parę elementów AJAX, aby przyciski powodowały jedynie pobranie nowych danych w miejscu gdzie się one zmieniają.
Na początku trzeba dodać definicję nowej przestrzeni nazw do elementu ui:composition (xmlns:a4j="http://richfaces.org/a4j"):
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j"
template="layout/template.xhtml">
Teraz muszę zaznaczyć fragment strony, który ma być odświeżany po wciśnięciu każdego z przycisków. W przypadku Begin muszę ponownie wyświetlić widoczne przyciski:
<div class="dialog">
<div class="prop">
<span class="name">Value</span>
<span class="value">
<a4j:outputPanel id="valueOutput">
#{SampleConversation.value}
</a4j:outputPanel>
</span>
</div>
</div>
Dla Increment należy odświeżyć wartość:
<h:form id="SampleConversation">
<div class="actionButtons">
<a4j:outputPanel id="buttonsOutput">
<h:commandButton id="begin" value="Begin"
action="#{SampleConversation.begin}"
rendered="#{not conversation.longRunning}"/>
<h:commandButton id="inc" value="Increment"
action="#{SampleConversation.increment}"
rendered="#{conversation.longRunning}"/>
<h:commandButton id="end" value="End"
action="#{SampleConversation.end}"
rendered="#{conversation.longRunning}"/>
</a4j:outputPanel>
</div>
</h:form>
Ponieważ przycisk End powoduje przejście na stronę home.seam, nie muszę się nim przejmować.
Pozostało jeszcze takie skonfigurowanie przycisków, aby odświeżały jedynie wybrany fragment strony. Jednak h:commandButton nie posiada takiej funkcji – należy użyć znacznika a4j:commandButton z wartością atrybutu reRender równą wartości id odświeżanego panelu a4j:outputPanel:
<a4j:commandButton id="begin" value="Begin"
action="#{SampleConversation.begin}"
rendered="#{not conversation.longRunning}"
reRender="buttonsOutput"/>
<a4j:commandButton id="inc" value="Increment"
action="#{SampleConversation.increment}"
rendered="#{conversation.longRunning}"
reRender="valueOutput"/>
I to już wszystko. Z początku różnica w działaniu może nie być zauważalna, ale wystarczy na początku dokumentu dodać jakiś duży obrazek, aby korzyści z wykorzystania AJAX były oczywiste:
<ui:define name="body">
<h:graphicImage value="http://upload.wikimedia.org/wikipedia/commons/3/39/Tux-peluche.jpg"/>
AJAX można z powodzeniem zastosować także na innych stronach. Na przykład doskonale nadaje się do przeglądania długiej listy rekordów tabeli. Ale o tym napiszę już innym razem.



