JSF 2 fu: Часть 3. Обработка событий, JavaScript и Ajax

Расширяем составные компоненты, используя другую новую функциональность JSF 2

Член экспертной группы Java™Server Faces (JSF) 2 Дэвид Джири завершает этой статьёй цикл из трех статей, посвященных новым возможностям JSF 2. Узнайте, как использовать новую событийную модель инфраструктуры, а также встроенную поддержку Ajax, позволяющую сделать ваши компоненты еще мощнее.

Дэвид Джири, президент, Clarity Training, Inc.

David GearyАвтор, лектор и консультант Дэвид Джири является президентом компании Clarity Training, Inc., Он обучает разработчиков создавать Web-приложения с использованием JSF и Google Web Toolkit (GWT). Он участвовал в экспертных группах JSTL 1.0 и JSF 1.0/2.0, был соавтором сертификационного экзамена Web Developer Certification Exam компании Sun, а также принимал участие в проектах с открытым кодом, в том числе Apache Struts и Apache Shale. Книга Дэвида Graphic Java Swing стала одной из самых продаваемых книг о Java, а Core JSF (в соавторстве с Кэем Хорстманом) - одна из самых продаваемых книг о JSF. Дэвид регулярно выступает на конференциях и встречах пользовательских групп. Он является регулярным участником конференций NFJS с 2003 года, проводил курсы в университете Java и дважды удостаивался звания JavaOne rock star.



02.02.2011

Одним из главных конкурентных преимуществ JSF является то, что эта инфраструктура основана на компонентах. Это означает, что она позволяет создавать компоненты, которые в дальнейшем можно использовать повторно. Этот мощный механизм повторного использования был в значительной степени недооценен в версии JSF 1, так как в ней было довольно сложно создавать компоненты.

Как мы видели в части 2, с помощью появившейся в JSF 2 новой функциональности составных компонентов можно легко создавать компоненты — для этого не нужно ни Java-кода, ни конфигурации. Возможно, эта функциональность является самой важной частью JSF 2, так как она позволяет реализовать весь потенциал компонентов JSF.

В этой, третьей и последней, статье о JSF 2 я покажу, как создавать из составных компонентов новую функциональность, используя новые средства обработки событий и работы с Ajax, также появившиеся в JSF 2. Кроме того, мы познакомимся со следующими советами по наиболее эффективному использованию JSF 2:

  • Совет 1: создавайте компоненты
  • Совет 2: используйте Ajax
  • Совет 3: показывайте ход выполнения работы

В первом совете мы бегло рассмотрим два компонента, которые мы уже обсуждали в части 2. В последующих советах мы увидим, как трансформировать эти компоненты с помощью Ajax и обработки событий.

Совет 1: Создаем компоненты

В приложении places, с которым мы познакомились в части 1, имеется несколько составных компонентов. Одним из таких компонентов является map, который отображает карту определенного места и выпадающее меню масштаба, как показано на рисунке 1:

Рисунок 1. Компонент map приложения places
The map component

В листинге 1 показан урезанный код компонента map:

Листинг 1. Компонент map
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
    ...
    xmlns:composite="http://java.sun.com/jsf/composite"
    xmlns:places="http://java.sun.com/jsf/composite/components/places">
    
   <!-- INTERFACE -->
   <composite:interface>
     <composite:attribute name="title"/>
   </composite:interface>
        
   <!-- IMPLEMENTATION --> 
   <composite:implementation">
     <div class="map">
       ...
       <h:panelGrid...>
         <h:panelGrid...>
            <h:selectOneMenu onchange="submit()"
                 value="#{cc.parent.attrs.location.zoomIndex}"
                 valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
                 style="font-size:13px;font-family:Palatino">
            
              <f:selectItems value="#{places.zoomLevelItems}"/>
                           
            </h:selectOneMenu>               
          </h:panelGrid>
        </h:panelGrid>   
        
        <h:graphicImage url="#{cc.parent.attrs.location.mapUrl}" 
          style="border: thin solid gray"/>  
       ...
      
     </div>
   ...
       
  </composite:implementation>    
</html>

Одной из замечательных особенностей компонентов является то, что их можно заменять более мощными версиями, не затрагивая при этом окружающую его функциональность. Например, на рисунке 2 я заменил компонент image из листинга 1 на компонент Google Maps, courtesy of GMaps4JSF (см. Ресурсы):

Рисунок 2. Карта на основе компонента image библиотеки GMaps4JSF
GMaps4JSF map component

В листинге 2 показана обновленная (и урезанная) версия кода компонента map:

Листинг 2. Заменяем компонент map компонентом GMaps4JSF
<h:selectOneMenu onchange="submit()"value="#{cc.parent.attrs.location.zoomIndex}"
              valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
              style="font-size:13px;font-family:Palatino">
     
  <f:selectItems value="#{places.zoomLevelItems}"/>
                    
</h:selectOneMenu>   

...         

<m:map id="map" width="420px" height="400px" 
     address="#{cc.parent.attrs.location.streetAddress}, ..." 
     zoom="#{cc.parent.attrs.location.zoomIndex}"
     renderOnWindowLoad="false">
     
  <m:mapControl id="smallMapCtrl" 
              name="GLargeMapControl" 
          position="G_ANCHOR_TOP_RIGHT"/>
          
  <m:mapControl  id="smallMapTypeCtrl" name="GMapTypeControl"/>                  
  <m:marker id="placeMapMarker"/>     
    
</m:map>

Для использования компонента GMaps4JSF я заменил тег <h:graphicImage> на тег <m:map> из набора компонентов GMaps4JSF. Также мы легко связали выпадающее меню масштаба с компонентом GMaps4JSF. Для этого мы указали в атрибуте zoom тега <m:map> нужное свойство bean-компонента.

Обратите внимание, что когда пользователь изменяет масштаб, я вызываю отправку формы с атрибутом onchange тега <h:selectOneMenu>, как показано в первой частично выделенной жирным шрифтом строке из листинга 1. Эта отправка формы запускает жизненный цикл JSF, в результате которого в свойство zoomIndex bean-компонента location,хранящегося в родительском составном компоненте, помещается новое значение масштаба. Это свойство bean-компонента привязано к компоненту ввода, показанному в первой строке листинга 2.

Я не указал перехода при отправке формы, ассоциированной с изменением масштаба, поэтому JSF после обработки запроса обновляет ту же самую страницу, перерисовывая карту в новом масштабе. Несмотря на то, что изменяется только карта, при обновлении перерисовывается вся страница. В совете 2: используем Ajax мы увидим, как с помощью Ajax можно в ответ на изменение масштаба перерисовывать только лишь карту.

Компонент login

Еще одним компонентом, используемым в приложении places, является компонент входа login. На рисунке 3 показана работа компонента login:

Рисунок 3. Компонент login
The login component

В листинге 3 показана разметка, с помощью которой создается компонент login, показанный на рисунке 3:

Листинг 3. Минимизированный компонент login только с обязательными атрибутами
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:util="http://java.sun.com/jsf/composite/components/util">

  <util:login loginAction="#{user.login}"
              managedBean="#{user}"/>
                
</ui:composition>

У компонента login имеется только два обязательных атрибута:

  • loginAction: метод дествия login
  • managedBean: управляемый bean-компонент со свойствами name и password

Управляемый bean-компонент из Listing 3 показан в листинге 4:

Листинг 4. User.groovy
package com.clarity

import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
 
@ManagedBean() 
@SessionScoped  
               
public class User {    
  private final String VALID_NAME     = "Hiro"
  private final String VALID_PASSWORD = "jsf"
  
  private String name, password;
 
  public String getName() { name }
  public void setName(String newValue) { name = newValue }
  
  public String getPassword() { return password }
  public void setPassword(String newValue) { password = newValue }  
  
  public String login() {
    "/views/places"
  }

  public String logout() {
    name = password = nameError = null
    "/views/login"
  }
}

Управляемый bean-компонент из листинга 4 написан на Groovy. Использование Groovy вместо Java не дает в данном случае больших преимуществ, кроме избавления от необходимости ставить точки с запятыми и инструкции return. Однако в совете 2, в разделе, посвященном валидации,мы узнаем и более убедительные причины использовать Groovy для управляемого bean-компонента User.

Все же в большинстве случаев компоненты login нужно конфигурировать полностью: с надписями и текстом на кнопке, как показано на рисунке 4:

Рисунок 4. Полностью сконфигурированный компонент login
A fully configured login component

В листинге 5 приведена разметка, с помощью которой сгенерирован компонент login, показанный на рисунке 4:

Листинг 5. Конфигурируем компонент login
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:util="http://java.sun.com/jsf/composite/components/util">
  
  <util:login loginPrompt="#{msgs.loginPrompt}"
               namePrompt="#{msgs.namePrompt}"
           passwordPrompt="#{msgs.passwordPrompt}"
          loginButtonText="#{msgs.loginButtonText}"
              loginAction="#{user.login}"          
              managedBean="#{user}"/>
                
</ui:composition>

В листинге 5 я получаю строки для надписей и текста кнопки login из ресурсов.

В листинге 6 приведено определение компонента login:

Листинг 6. Определение компонента login
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<!-- Usage:

  <util:login loginPrompt="#{msgs.loginPrompt}"
               namePrompt="#{msgs.namePrompt}"
           passwordPrompt="#{msgs.passwordPrompt}"
          loginButtonText="#{msgs.loginButtonText}"
              loginAction="#{user.login}"
              managedBean="#{user}">
                 
    <f:actionListener for="loginButton" 
                     type="com.clarity.LoginActionListener"/>
                            
  </util:login>

  managedBean must have two properties: name and password. 
  
  The loginAction attribute must be an action method that takes no
  arguments and returns a string. That string is used to navigate
  to the page the user sees after logging in.
  
  This component's loginButton is accessible so that you can
  add action listeners to it, as depicted above. The class specified
  in f:actionListener's type attribute must implement the
  javax.faces.event.ActionListener interface.
  
 -->
 
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:composite="http://java.sun.com/jsf/composite">
    
  <!-- INTERFACE -->
  <composite:interface>
  
    <!-- PROMPTS -->
    <composite:attribute name="loginPrompt"/>
    <composite:attribute name="namePrompt"/>
    <composite:attribute name="passwordPrompt"/>
    
    <!--  LOGIN BUTTON -->      
    <composite:attribute name="loginButtonText"/>
    
    <!-- loginAction is called when the form is submitted -->
    <composite:attribute name="loginAction" 
             method-signature="java.lang.String login()"
                     required="true"/>
                     
    <!-- You can add listeners to this actionSource:  -->
    <composite:actionSource name="loginButton" targets="form:loginButton"/>
      
    <!-- BACKING BEAN -->
    <composite:attribute name="managedBean" required="true"/>
  </composite:interface>
    
  <!-- IMPLEMENTATION -->
  <composite:implementation>
    <div class="prompt">
      #{cc.attrs.loginPrompt}
    </div>
    
    <!-- FORM -->       
    <h:form id="form">
      <h:panelGrid columns="2">
      
        <!-- NAME AND PASSWORD FIELDS -->
        #{cc.attrs.namePrompt}
        <h:inputText id="name" 
                  value="#{cc.attrs.managedBean.name}"/>
    
        #{cc.attrs.passwordPrompt} 
        <h:inputSecret id="password" size="8" 
          value="#{cc.attrs.managedBean.password}"/>
          
      </h:panelGrid>
    
      <p>
        <!-- LOGIN BUTTON -->    
        <h:commandButton id="loginButton"
          value="#{cc.attrs.loginButtonText}"
          action="#{cc.attrs.loginAction}"/>
      </p>
    </h:form>    
  </composite:implementation>
</html>

Так же как и компонент map, компонент login можно улучшить, задействовав Ajax. В следующем совете о валидации я покажу, как с помощью Ajax добавить в компонент login проверку вводимых данных.


Совет 2: используйте Ajax

Технология Ajax обычно требует выполнения двух шагов, которые, как правило, не выполняются для не-Ajax HTTP-запросов: частичная обработка форм на сервере и последующее частичное отображение объектной модели документа (DOM, Document Object Model) на клиенте.

Частичная обработка и отображение

JSF 2 поддерживает частичную обработку и отображение за счет разбиения жизненного цикла JSF на две части: выполнение и отображение. На рисунке 5 показана часть, относящаяся к выполнению:

Рисунок 5. Фаза выполнения жизненного цикла JSF
Execute portion of the life cycle

На рисунке 6 показана фаза отображения жизненного цикла JSF:

Рисунок 6. Фаза отображения жизненного цикла JSF
Render portion of the life cycle

Идея, лежащая в основе разделения жизненного цикла на фазы выполнения и отображения, довольно проста: можно указывать компоненты, которые JSF будет выполнять на сервере, а также компоненты, которые JSF будет перерисовывать при возвращении Ajax-ответа. Это делается с помощью появившегося в JSF 2 тега <f:ajax>, как показано в листинге 7:

Листинг 7. Меню масштаба с использованием Ajax
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
     value="#{cc.parent.attrs.location.zoomIndex}"
     style="font-size:13px;font-family:Palatino">

  <f:ajax event="change" execute="@this" render="map"/>
  <f:selectItems value="#{places.zoomLevelItems}"/>
             
</h:selectOneMenu>             
     
<m:map id="map"...>

Листинг 7 представляет собой модификацию меню, показанного в первой строке листинга 2: я удалил из листинга 2 атрибут onchange и добавил тег <f:ajax>. В этом теге <f:ajax> указывается:

  • событие, при наступлении которого осуществляется Ajax-запрос
  • компонент, который выполняется на сервере
  • компонент, отображающий ответ на клиенте

Когда пользователь выбирает значение в меню масштаба, JSF делает Ajax-запрос на сервер. Далее JSF пропускает меню через фазу выполнения жизненного цикла (@this обозначает компонент, заключающий в себе тег <f:ajax>), и обновляет у меню свойство zoomIndex на этапе обновления данных модели. При получении Ajax-ответа JSF перерисовывает компонент map, в котором используется (вновь заданный) коэффициент масштабирования. Таким образом, добавив одну строку XHTML-кода, мы получили меню масштаба, использующее Ajax.

Однако все можно сделать еще проще, так как JSF предоставляет значения по умолчанию для атрибутов event и execute.

У каждого компонента JSF есть событие по умолчанию, при наступлении которого посылается Ajax-запрос, если внутри тега компонента имеется тег <f:ajax>. Для меню – это событие change. Это означает, что можно избавиться от атрибута event тега <f:ajax>, показанного в листинге 7. Значением по умолчанию для атрибута execute тега <f:ajax> является @this, обозначающее компонент, внутри которого находится тег <f:ajax>.В нашем примере этим компонентом является меню, поэтому атрибут execute можно также опустить.

Используя для атрибутов тега <f:ajax> значения по умолчанию, можно сократить листинг 7 до кода, показанного в листинге 8:

Листинг 8. Упрощенная версия меню масштаба использующего Ajax
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
     value="#{cc.parent.attrs.location.zoomIndex}"
     style="font-size:13px;font-family:Palatino">

  <f:ajax render="map"/>
  <f:selectItems value="#{places.zoomLevelItems}"/>
             
</h:selectOneMenu>             

<m:map id="map"...>

Вот так легко JSF 2 позволяет добавлять в компоненты технологию Ajax. Конечно, предыдущий пример очень простой - при изменении пользователем масштаба мы просто перерисовываем одну карту, а не всю страницу. В следующем разделе мы рассмотрим пример более сложной операции - проверку отдельных полей формы.

Проверка данных

Полезно проверять поля формы и при наличии ошибки сразу же информировать пользователя. Например, на рисунке 7 показано использование Ajax для проверки поля с именем пользователя:

Рисунок 7. Проверка имени пользователя с помощью Ajax
Ajax validation

Разметка, соответствующая полю для имени пользователя, показана в листинге 9:

Листинг 9. Поле имени пользователя
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:panelGrid columns="2">
  #{cc.attrs.namePrompt}
  <h:panelGroup>
    <h:inputText id="name" value="#{cc.attrs.managedBean.name}"
       valueChangeListener="#{cc.attrs.managedBean.validateName}">
       
       <f:ajax event="blur" render="nameError"/>
       
     </h:inputText>
     
     <h:outputText id="nameError" 
       value="#{cc.attrs.managedBean.nameError}"
       style="color: red;font-style: italic;"/>
  </h:panelGroup>     
  ... 
</h:panelGrid>

Мы снова используем тег <f:ajax>, однако в этот раз вместо события по умолчанию для полей ввода — change — мы указываем событие blur. Когда пользователь покидает поле ввода имени, JSF посылает на сервер Ajax-запрос и пропускает компонент ввода name через фазу выполнения жизненного цикла. Это означает, что на этапе проверки данных жизненного цикла JSF будет вызывать обработчик изменения значения поля name, указанный в листинге 9. В листинге 10 показан этот обработчик изменения значения:

Листинг 10. Метод validateName()
package com.clarity

import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent 
import javax.faces.component.UIInput 
 
@ManagedBean()  
@SessionScoped    
       
public class User {    
  private String name, password, nameError;
 
  ...
  
  public void validateName(ValueChangeEvent e) {
    UIInput nameInput = e.getComponent()
    String name = nameInput.getValue()
    
    if (name.contains("_"))   nameError = "Name cannot contain underscores"
    else if (name.equals("")) nameError = "Name cannot be blank"
    else                      nameError = "" 
  }
  
  ...
}

Обработчик изменения значения — метод validateName() управляемого bean-компонента user — проверяет поле name и обновляет свойство nameError управляемого bean-компонента user.

После получения Ajax-ответа, в зависимости от атрибута render тега <f:ajax>, показанного в листинге 9, JSF выводит сообщение nameError. Текст этого сообщения хранится в свойстве nameError управляемого bean-компонента user.

Проверка нескольких полей

В предыдущей секции мы узнали, как выполнять Ajax-валидацию одного поля. Однако иногда нужно проверять за один раз значения нескольких полей. Например, на рисунке 8 показано, как приложение places проверяет совместно значения полей name и password:

Рисунок 8. Проверяем несколько полей
Validating multiple fields

Я проверяю поля name и password, когда пользователь отправляет форму, поэтому в этом примере Ajax не нужен. Вместо этого мы воспользуемся новой системой событий JSF 2, как показано в листинге 11:

Листинг 11. используем тег <f:event>
<h:form id="form" prependId="false">
  
  <f:event type="postValidate" 
       listener="#{cc.attrs.managedBean.validate}"/>
  ...
</h:form>

<div class="error" style="padding-top:10px;">
  <h:messages layout="table"/>
</div>

В листинге 11 я использую еще один новый (как и <f:ajax> ) тег JSF 2 <f:event>. Тег <f:event> похож на тег <f:ajax> еще и в том, что его просто использовать.

Поместите тег <f:event> внутрь тега компонента, и тогда при наступлении указанного (в атрибуте type) события JSF вызовет метод, указанный в атрибуте listener. Итак, на человеческом языке тег<f:event> из Листинга 11 означает следующее: после проверки формы, надо вызвать метод validate() управляемого bean-компонента, который пользователь передал в этот составной компонент. Этот метод показан в листинге 12:

Листинг 12. Метод validate()
package com.clarity

import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent 
import javax.faces.component.UIInput 
 
@ManagedBean()  
@SessionScoped    
       
public class User {    
  private final String VALID_NAME     = "Hiro";
  private final String VALID_PASSWORD = "jsf";
  
  ...
  
  public void validate(ComponentSystemEvent e) {
    UIForm form = e.getComponent() 
    UIInput nameInput = form.findComponent("name")
    UIInput pwdInput = form.findComponent("password")
    
    if ( ! (nameInput.getValue().equals(VALID_NAME) &&
        pwdInput.getValue().equals(VALID_PASSWORD))) {
      
      FacesContext fc = FacesContext.getCurrentInstance()
      fc.addMessage(form.getClientId(), 
        new FacesMessage("Name and password are invalid. Please try again."))
      fc.renderResponse()
    }
  }
  
  ...
}

JSF передает в метод validate(), показанный в листинге 12, событие компонентной системы, из которого метод получает ссылку на компонент, где произошло событие — т.е. на форму входа в приложение. Далее с помощью метода findComponent() я нахожу в форме компоненты name и password. Если значения этих компонентов не равны Hiro и jsf соответственно, я помещаю в контекст faces сообщение и командую JSF немедленно перейти к этапу вывода ответа. Таким образом, я пропускаю этап обновления данных модели, на котором неправильные имя пользователя и пароль попали бы в модель (см. рисунок 5).

Возможно, вы заметили, что методы проверки, показанные в листинге 10 и листинге 12, написаны на Groovy. В отличие от листинга 4, в котором единственным преимуществом использования Groovy было избавление от точек с запятой и инструкций return, код Groovy в листинге 10 и листинге 12 освобождает меня еще и от приведения типов. Например, в листинге 10ComponentSystemEvent.getComponent() и UIComponent.findComponent()возвращают значения типа UIComponent. В Java мне пришлось бы явно выполнять приведение типов значений, возвращаемых этими методами, а Groovy делает это приведение за меня.


Совет 3: показываем ход выполнения работы

В разделе Используте Ajax мы увидели, как добавить Ajax в меню масштаба компонента map, чтобы приложение places при изменении масштаба перерисовывало только карту. Еще одним типичным способом использования Ajax является предоставление пользователю информации о ходе выполнения задачи, например, так, как показано на рисунке 9:

Рисунок 9. Индикатор выполнения
A progress bar

На рисунке 9 я заменил меню масштаба анимированным GIF-изображением, которое показывается при выполнении Ajax-запроса. При завершении обработки Ajax-запроса я заменяю индикатор выполнения на меню масштаба. В листинге 13 показано, как это делается:

Листинг 13. Мониторинг Ajax-запроса
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
     value="#{cc.parent.attrs.location.zoomIndex}"
     style="font-size:13px;font-family:Palatino">

  <f:ajax render="map" onevent="zoomChanging"/>
  <f:selectItems value="#{places.zoomLevelItems}"/>

  ...             
</h:selectOneMenu>
...
<h:graphicImage id="progressbar" style="display: none" 
              library="images" name="orange-barber-pole.gif"/>

В листинге 13 я добавил изображение шкалы выполнения, которое изначально скрыто, и указал атрибут onevent тега <f:ajax>. Этот атрибут ссылается на JavaScript-функцию, показанную в листинге 14. JSF вызывает эту функцию, когда Ajax-запрос, посланный в листинге 13 находится в обработке:

Листинг 14. JavaScript-функция, отвечающая на Ajax-запрос
function zoomChanging(data) {
  var menuId = data.source.id;
  var progressbarId = menuId.substring(0, menuId.length - "menu".length)
      + "progressbar";

  if (data.name == "begin") {
    Element.hide(menuId);
    Element.show(progressbarId);
  } 
  else if (data.name == "success") {
    Element.show(menuId);
    Element.hide(progressbarId);
  }
}

JSF передает в функцию из листинга 14 объект, содержащий такую информацию, как клиентский идентификатор компонента, на котором произошло событие (в данном случае, меню масштаба) и текущий статус Ajax-запроса, представленный неудачно названным свойством name.

Функция zoomChanging(), показанная в листинге 14,вычисляет клиентский идентификатор изображения индикатора выполнения и с помощью объекта Element библиотеки Prototype скрывает или показывает во время Ajax-вызова соответствующие HTML-элементы.


Заключение

За время своего существования JSF 1 приобрела репутацию трудной в использовании инфраструктуры. Во многом эта репутация заслуженна. JSF 1 разрабатывалась «в башне из слоновой кости» без оглядки на прошлый опыт, который могло бы дать практическое использование. В результате реализация приложений и компонентов с помощью JSF была гораздо сложнее, чем следовало бы.

JSF 2, напротив, была создана в результате решения практических задач людьми, которые занимались проектами с открытым кодом на основе JSF 1. Применение практического опыта привело к появлению гораздо более умной инфраструктуры, позволяющей легко создавать надежные приложения с поддержкой Ajax.

В этом цикле статей я рассказал о самой важной функциональности JSF 2, такой как аннотации и соглашения, заменяющие конфигурацию, упрощенная навигация, поддержка ресурсов, составные компоненты, встроенная поддержка Ajax и расширенная модель событий. Однако в JSF 2 имеется множество возможностей, о которых мы не рассказали в этом цикле, например области видимости Представления и Страницы, страницы, поддерживающие закладки, а также параметр Project Stage. Все эти и многие другие возможности делают JSF 2 намного лучше своего предшественника.


Загрузка

ОписаниеИмяРазмер
Исходный код примеров этой статьиj-jsf2-fu-3.zip7.7 МБ

Ресурсы

Научиться

Получить продукты и технологии

  • JSF: загрузите JSF 2.0.(EN)
  • Загрузите GMaps4JSF.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=620711
ArticleTitle=JSF 2 fu: Часть 3. Обработка событий, JavaScript и Ajax
publish-date=02022011