楼主: Sky-Tiger

JSF 2 : Event handling, JavaScript, and Ajax

[复制链接]
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
11#
 楼主| 发表于 2009-7-24 22:10 | 只看该作者
Figure 6 highlights the JSF life cycle's render portion:

Figure 6. The render portion of the JSF life cycle
Render portion of the life cycle

IMG01.gif (7.46 KB, 下载次数: 10)

IMG01.gif

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
12#
 楼主| 发表于 2009-7-24 22:10 | 只看该作者
The idea behind the life cycle's execute and render portions is simple: you can specify components that JSF executes (processes) on the server, and components that JSF renders when an Ajax call returns. You do that with <f:ajax>, which is new for JSF 2, as shown in Listing 7:

Listing 7. An Ajax zoom menu

<!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"...>


Listing 7 is a modification of the menu shown in the first line of Listing 2: I've removed the onchange attribute from Listing 2 and added an <f:ajax> tag. That <f:ajax> tag specifies:

    * The event that triggers the Ajax call
    * A component to execute on the server
    * A component to render on the client

When the user selects an item from the zoom menu, JSF makes an Ajax call to the server. Subsequently, JSF passes the menu through the life cycle's execute portion (@this signifies <f:ajax>'s surrounding component), and updates the menu's zoomIndex during the Update Model Values phase of the life cycle. When the Ajax call returns, JSF renders the map component, which uses the (newly set) zoom index to redraw the map, and now you have an Ajaxified zoom menu with the addition of one line of XHTML.

But things can get simpler still, because JSF provides default values for the event and execute attributes.

Each JSF component has a default event that triggers Ajax calls if you embed an <f:ajax> tag inside the component tag. For menus, that event is the change event. That means I can get rid of the <f:ajax>'s event attribute in Listing 7. The default for <f:ajax>'s execute attribute is @this, which signifies <f:ajax>'s surrounding component. In this example, that component is the menu, so I can also get rid of the execute attribute.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
13#
 楼主| 发表于 2009-7-24 22:10 | 只看该作者
By using default attribute values for <f:ajax>, I can reduce Listing 7 to Listing 8:

Listing 8. Simpler version of an Ajax zoom menu

<!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"...>


That's how easy it is to add Ajax to your components with JSF 2. Of course, the preceding example is pretty simple: I am simply redrawing only the map instead of the entire page when the user selects a zoom level. Some operations, such as validating individual fields in a form, are more complicated, so next I'll tackle that use case.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
14#
 楼主| 发表于 2009-7-24 22:10 | 只看该作者
Validation

It's a good idea to validate fields, and provide immediate feedback, when a user tabs out of a field. For example, in Figure 7, I'm using Ajax to validate the name field:

Figure 7. Ajax validation
Ajax validation

The markup for the name field is shown in Listing 9:

Listing 9. The name field

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<hanelGrid columns="2">
  #{cc.attrs.namePrompt}
  <hanelGroup>
    <h:inputText id="name" value="#{cc.attrs.managedBean.name}"
       valueChangeListener="#{cc.attrs.managedBean.validateName}">
      
       <f:ajax event="blur" render="nameError"/>
      
     </h:inputText>
     
     <hutputText id="nameError"
       value="#{cc.attrs.managedBean.nameError}"
       style="color: red;font-style: italic;"/>
  </hanelGroup>     
  ...
</hanelGrid>


Once again, I use <f:ajax>, only this time the default event for inputs — change — won't do, so I specify blur for the event that triggers the Ajax call. When the user tabs out of the name field, JSF makes an Ajax call to the server and runs the name input component through the execute portion of the life cycle. This means that JSF will invoke the name input's value-change listener specified in Listing 9 during the Process Validations phase of the life cycle. Listing 10 shows that value-change listener:

Listing 10. The validateName() method

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 = ""
  }
  
  ...
}


The value-change listener — the user managed bean's validateName() method — validates the name field and updates the user managed bean's nameError property.

After the Ajax call returns, by virtue of the render attribute of the <f:ajax> tag in Listing 9, JSF renders the nameError output. That output shows the user managed bean's nameError property.

1英语.jpg (13.66 KB, 下载次数: 4)

1英语.jpg

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
15#
 楼主| 发表于 2009-7-24 22:11 | 只看该作者
Multifield validation

In the preceding subsection, I showed you how to perform Ajax validation on a single field. Sometimes, though, you need to validate multiple fields at the same time. For example, Figure 8 shows the places application validating the name and password fields together:

Figure 8. Validating multiple fields
Validating multiple fields

I validate the name and password fields together when the user submits the form, so I don't need Ajax for this example. Instead I will use JSF 2's new event system, as shown in Listing 11:

Listing 11. Using <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>


In Listing 11, I use <f:event>, which — like <f:ajax> — is new for JSF 2. The <f:event> tag is similar to <f:ajax> in another respect, too: it's simple to use.

You put an <f:event> tag inside a component tag, and when the specified event (specified with the type attribute) occurs to that component, JSF invokes a method, specified with the listener attribute. So, in English, what the <f:event> tag in Listing 11 means is: After validating the form, invoke the validate() method on the managed bean that the user passed to this composite component. That method is shown in Listing 12:

Listing 12. The validate() method

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 passes the validate() method in Listing 12 a component system event, from which the method obtains a reference to the component the event applies to — the login form. From the form, I use the findComponent() method to get the name and password components. If those components' values are not Hiro and jsf, respectively, I store a message on the faces context and tell JSF to proceed immediately to the life cycle's Render Response phase. This way, I avoid the Update Model Values phase, which would push the bad name and password through to the model (see Figure 5).

You may have noticed that the validation methods in Listing 10 and Listing 12 are written in Groovy. Unlike Listing 4, where the only advantage to using Groovy was freedom from semicolons and return statements, the Groovy code in Listing 10 and Listing 12 frees me from casting. For example, in Listing 10, ComponentSystemEvent.getComponent() and UIComponent.findComponent() both return type UIComponent. With the Java language, I would have to cast the return values of those methods. Groovy does the casting for me.

1英语.jpg (15.14 KB, 下载次数: 8)

1英语.jpg

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
16#
 楼主| 发表于 2009-7-24 22:11 | 只看该作者
Tip 3: Show progress

In Ajaxify, I showed you how to Ajaxify the zoom menu for the map component, so that the places application redraws only the map portion of the page when the user changes the zoom level. Another common Ajax use case is to provide some feedback to the user that an Ajax event is progressing, as shown in Figure 9:

Figure 9. A progress bar
A progress bar

In Figure 9, I've replaced the zoom menu with an animated GIF that displays while the Ajax call progresses. When the Ajax call is complete, I replace the progress indicator with the zoom menu. Listing 13 shows how it's done:

Listing 13. Monitoring an Ajax request

<!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"/>


In Listing 13, I add a progress-bar image, which is initially not displayed, and specify the onevent attribute for <f:ajax>. That attribute references a JavaScript function, shown in Listing 14, that JSF calls while the Ajax call initiated in Listing 13 progresses:

Listing 14. JavaScript that responds to an Ajax request

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 passes the function in Listing 14 an object that contains some information, such as the client identifier of the component that fired the event (in this case, the zoom-level menu), and the current status of the Ajax request, represented by the poorly named name property.

The zoomChanging() function shown in Listing 14 calculates the client identifier of the progress bar image and then uses the Prototype Element object to hide and show the appropriate HTML elements during the Ajax call.

1英语.jpg (77.03 KB, 下载次数: 5)

1英语.jpg

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
17#
 楼主| 发表于 2009-7-24 22:11 | 只看该作者
Conclusion

Over the years, JSF 1 developed a reputation as a framework that was difficult to use. In many respects, that reputation was deserved. JSF 1 was developed in an ivory tower without the considerable hindsight that real-world use affords. As a result, JSF made it much more difficult to implement applications and components than it should have been.

JSF 2, on the other hand, was born from the crucible of real-world experience, by folks who implemented open source projects on top of JSF 1. That real-world hindsight resulted in a much more savvy framework that makes it easy to implement robust, Ajaxified applications.

Throughout this series, I've shown you some of the most prominent JSF 2 features, such as annotations and convention that replace configuration, simplified navigation, support for resources, composite components, built-in Ajax, and the expanded event model. But JSF 2 has many more features that I did not cover in this series, such as View and Page scopes, support for bookmarkable pages, and Project Stage. All those features, and more, make JSF 2 a vast improvement over its predecessor.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
18#
 楼主| 发表于 2009-7-24 22:13 | 只看该作者
Abstract

GMaps4JSF aims at integrating Google maps with JSF. JSF users will be also able to construct complex Streetview Panoramas and Maps with just few lines of code (JSF tags).

GMaps4JSF is one of the JSF Mashups libraries that enables JSF users to build web 2.0 mashup applications in JSF easily.

The library provides JSF tags that make it easy to

    * Create the map using (latitude and longitude) or (address).
    * Add marker(s) to the map.
    * Add information text(s) to the map.
    * Add control(s) to the map.
    * Create event listener(s) on the map objects.
    * Draw polyline(s) on the map.
    * Draw polygon(s) on the map.
    * Add groundOverlay(s) on the map.
    * Perform different operations on the map like zoom in and out, switching between map types, ...etc.
    * Create a Streetview Panorama and integrate it simply with the map.

#
# Add information text(s) to the map.
# Add control(s) to the map.
# Create event listener(s) on the map objects.
# Draw polyline(s) on the map.
# Draw polygon(s) on the map.
# Add groundOverlay(s) on the map.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
19#
 楼主| 发表于 2009-7-24 22:13 | 只看该作者
What is new in GMaps4JSF 1.1.2

    * Complete integration with JSF 2.0 Ajax.
    * Map autoReshape feature.
    * Having a Maven2 repository for the library artifacts.
    * Supporting server side events for the library components not just client side events.
    * adding (showLocationNotFoundMessage) attribute to the map and marker components. To determine whether to show an error message when the location is not found.
    * Fixing markers' issues with IE8.
    * Fixing XHTML compliance issues.
    * Fixing the polygon issue inside the facelets <ui:repeat> tag.
    * Fixing the markers statelessness issue.
    * Fixing icon coordAnchor issue.
    * Fixing supporting client side events for HTMLInformationWindow.

使用道具 举报

回复
论坛徽章:
350
2006年度最佳版主
日期:2007-01-24 12:56:49NBA大富翁
日期:2008-04-21 22:57:29地主之星
日期:2008-11-17 19:37:352008年度最佳版主
日期:2009-03-26 09:33:53股神
日期:2009-04-01 10:05:56NBA季后赛大富翁
日期:2009-06-16 11:48:01NBA季后赛大富翁
日期:2009-06-16 11:48:01ITPUB年度最佳版主
日期:2011-04-08 18:37:09ITPUB年度最佳版主
日期:2011-12-28 15:24:18ITPUB年度最佳技术原创精华奖
日期:2012-03-13 17:12:05
20#
 楼主| 发表于 2009-7-24 22:13 | 只看该作者
What is new in GMaps4JSF 1.1.1

    * Adding the icon component to simplify the marker image customization.
    * Allowing adding notes to the marker component, and adding the (showInformationEvent) attribute to the marker component.
    * Direct Facelets support.
    * Enable adding events to the HTMLInformationWindow component using the eventListener component.
    * Adding (address) attribute to the streetViewPanorama component.
    * Adding (address) attribute to the marker component.
    * Facelets <ui:repeat> support.
    * Solving 1.1.0 defects.

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表