JSF Component Behaviors
-
Upload
andy-schwartz -
Category
Technology
-
view
116 -
download
7
description
Transcript of JSF Component Behaviors
JSF Component Behaviors
JSF Component Behaviors
Andy Schwartz | Oracle Corporation
JSF Component Behaviors
Agenda History Behavior API: Basics A Simple Sample Behavior Behavior API: Advanced Topics Auto Suggest Sample Behavior Future
JSF Component Behaviors
History
JSF Component Behaviors
First First, there was Ajax. And it was good. But it required JavaScript code.
JSF Component Behaviors
Sample: Ajax JavaScript API
<h:outputScript name="jsf.js" library="javax.faces"/>
<h:commandButton value="Do something Ajaxy"
onclick="jsf.ajax.request(this, event,
{render: 'out'}); return false;"/>
<h:outputText id=”out” value=”Update me!”/>
<h:outputScript name="jsf.js" library="javax.faces"/>
<h:commandButton value="Do something Ajaxy"
onclick="jsf.ajax.request(this, event,
{render: 'out'}); return false;"/>
<h:outputText id=”out” value=”Update me!”/>
JSF Component Behaviors
Ajax JavaScript API The Good
– Standard– Flexible
The Bad– Verbose– Error-prone
JSF Component Behaviors
Time for a declarative Ajax API
JSF Component Behaviors
Declarative Ajax, Take 1
New Components?
JSF Component Behaviors
Sample: New Components?
<h:commandButton value=“Not Ajax”/>
<a:commandButton value=“Ajax!”/>
<h:commandButton value=“Not Ajax”/>
<a:commandButton value=“Ajax!”/>
JSF Component Behaviors
New Components? The Good
– Simple– Familiar
The Bad– Component explosion– Next feature: more components?
JSF Component Behaviors
Declarative Ajax, Take 2
New Attributes?
JSF Component Behaviors
Sample: New Attributes?
<h:commandButton ajax=“true”/><h:commandButton ajax=“true”/>
JSF Component Behaviors
New Attributes? The Good
– Simple– No new components
The Bad– Attribute explosion– Next feature: more attributes?
JSF Component Behaviors
Declarative Ajax, Take 3
Attached Objects?
Remember those?
JSF Component Behaviors
What Are Attached Objects?
Attached objects enhance components with functionality not anticipated by the original component author.
JSF Component Behaviors
Some Existing Attached Objects Converters
– f:convertNumber– f:convertDateTime
Validators– f:validateLength– f:validateBean– f:validateRegex
JSF Component Behaviors
Ajax Attached Object?
<!-- We already do this…-->
<h:inputText>
<f:convertNumber/>
</h:inputText>
<!-- Why not this? -->
<h:commandButton>
<f:ajax/>
</h:commandButton>
<!-- We already do this…-->
<h:inputText>
<f:convertNumber/>
</h:inputText>
<!-- Why not this? -->
<h:commandButton>
<f:ajax/>
</h:commandButton>
JSF Component Behaviors
Ajax Attached Object
Yes!
JSF Component Behaviors
Ajax Attached Object The Good
– Easy to use– Familiar pattern– No attribute explosion– No component explosion– Some precedent exists
– Think a4j:support as attached object instead of component
The Bad– More verbose than component/attribute alternatives– Somebody needs to design the API!
JSF Component Behaviors
Behavior API: Basics
JSF Component Behaviors
API Requirements
Loose Coupling
Surprise?
JSF Component Behaviors
Loose Coupling Components should not contain Ajax-specific code Objects contribute scripts to component markup Components know where to insert attached scripts Objects may be attached to arbitrary components Objects may implement arbitrary behaviors
– Not limited to Ajax
JSF Component Behaviors
Two New Contracts
ClientBehavior ClientBehaviorHolder
JSF Component Behaviors
ClientBehavior Contract
String getScript(ClientBehaviorContext)
JSF Component Behaviors
ClientBehavior Scripts
What can a ClientBehavior script do?
JSF Component Behaviors
Say Hello
// Some people *always* start with “Hello, World!” public String getScript(ClientBehaviorContext c) { return “alert(‘Hello, World!’)”; }
// Some people *always* start with “Hello, World!” public String getScript(ClientBehaviorContext c) { return “alert(‘Hello, World!’)”; }
JSF Component Behaviors
Ajax
// Slightly more interesting public String getScript(ClientBehaviorContext c) { return “jsf.ajax.request(this, event)”; }
// Slightly more interesting public String getScript(ClientBehaviorContext c) { return “jsf.ajax.request(this, event)”; }
JSF Component Behaviors
What Else? Client-side validation DOM manipulation Tooltips, hover content Disclosures Logging Confirmation Key handling Auto-suggest
JSF Component Behaviors
Who Calls getScript()?
Components/Renderers call getScript() during rendering and insert scripts into the generated markup.
JSF Component Behaviors
Standard ClientBehaviors Just one for now
– Java API: AjaxBehavior– Tag API: <f:ajax>
JSF Component Behaviors
Attaching ClientBehaviors
Remember EditableValueHolder?
JSF Component Behaviors
ClientBehaviorHolder Contract
void addClientBehavior(
String eventName,
ClientBehavior behavior)
void addClientBehavior(
String eventName,
ClientBehavior behavior)
JSF Component Behaviors
What Events? Components define available events/attach points Behavior events can correspond to DOM events Events can also be “logical” (component-level) Some obvious events:
– h:commandButton: click– h:inputText: change
Some less obvious events– h:commandButton: focus, blur– h:inputText: keyup, keydown, keypress– h:panelGroup: mouseover, mouseout– foo: bar
JSF Component Behaviors
ClientBehaviorHolder Contract
Collection<String> getEventNames();Collection<String> getEventNames();
JSF Component Behaviors
Usage
<h:commandButton>
<f:ajax event=“focus”/>
</h:commandButton>
<h:inputText>
<f:ajax event=“keypress”/>
</h:inputText>
<h:panelGroup>
<foo:showHoverContent event=“mouseover”/>
</h:panelGroup>
<h:commandButton>
<f:ajax event=“focus”/>
</h:commandButton>
<h:inputText>
<f:ajax event=“keypress”/>
</h:inputText>
<h:panelGroup>
<foo:showHoverContent event=“mouseover”/>
</h:panelGroup>
JSF Component Behaviors
Logical Events Some components expose logical events Command: action (not DOM click) Input: valueChange (not DOM change) Client-side event abstraction over DOM Hides arbitrary DOM implementations Matches server-side abstraction Helpful in wrapping scenarios
JSF Component Behaviors
Logical Events
<!-- "click" event doesn't work if we want to target command components exclusively.--><f:ajax event="click"> <h:panelGroup> <h:commandButton/> <h:inputText/> <h:commandButton/> </h:panelGroup></f:ajax>
<!-- "click" event doesn't work if we want to target command components exclusively.--><f:ajax event="click"> <h:panelGroup> <h:commandButton/> <h:inputText/> <h:commandButton/> </h:panelGroup></f:ajax>
JSF Component Behaviors
Logical Events
<!-- Use logical "action" event instead. --><f:ajax event="action"> <h:panelGroup> <h:commandButton/> <h:inputText/> <h:commandButton/> </h:panelGroup></f:ajax>
<!-- Use logical "action" event instead. --><f:ajax event="action"> <h:panelGroup> <h:commandButton/> <h:inputText/> <h:commandButton/> </h:panelGroup></f:ajax>
JSF Component Behaviors
Default Events
What happens if you do not specify an event?
JSF Component Behaviors
ClientBehaviorHolder Contract
String getDefaultEventName();String getDefaultEventName();
JSF Component Behaviors
Default Event Usage
<h:commandButton> <!-- Default event: action --> <f:ajax/></h:commandButton>
<h:inputText> <!-- Default event: value change --> <f:ajax/></h:inputText>
<h:panelGroup> <!-- No default event defined: Boom! --> <f:ajax/></h:panelGroup>
<h:commandButton> <!-- Default event: action --> <f:ajax/></h:commandButton>
<h:inputText> <!-- Default event: value change --> <f:ajax/></h:inputText>
<h:panelGroup> <!-- No default event defined: Boom! --> <f:ajax/></h:panelGroup>
JSF Component Behaviors
More Event Fun: Chaining
<h:commandButton> <foo:confirm/> <f:ajax/></h:commandButton>
<h:commandButton> <foo:confirm/> <f:ajax/></h:commandButton>
JSF Component Behaviors
More Event Fun: Multiple Events
<h:commandButton> <f:ajax/> <foo:showHoverContent event=“mouseover”/> <foo:hideHoverContent event=“mouseout”/></h:commandButton>
<h:commandButton> <f:ajax/> <foo:showHoverContent event=“mouseover”/> <foo:hideHoverContent event=“mouseout”/></h:commandButton>
JSF Component Behaviors
Standard ClientBehaviorHolders
All standard components implement ClientBehaviorHolder.
JSF Component Behaviors
A Simple Sample Behavior
JSF Component Behaviors
Our Simple Sample Behavior
Confirm Behavior
JSF Component Behaviors
Step 1: Implement the Behavior Extend ClientBehaviorBase Implement getScript()
JSF Component Behaviors
ConfirmBehavior
public class ConfirmBehavior
extends ClientBehaviorBase {
@Override
public String getScript(
ClientBehaviorContext behaviorContext) {
return "return confirm('Are you sure?')";
}
}
public class ConfirmBehavior
extends ClientBehaviorBase {
@Override
public String getScript(
ClientBehaviorContext behaviorContext) {
return "return confirm('Are you sure?')";
}
}
JSF Component Behaviors
Step 2: Register the Behavior Two ways to do this
– Old School: faces-config.xml– New School: annotations
Both call Application.addBehavior(String, Class)– Associates Behavior class with a behavior id.– Enables Application.createBehavior(String)
JSF Component Behaviors
Register Behavior: Old School<faces-config>
<behavior> <behavior-id>jsf2foo.behavior.Confirm</behavior-id>
<behavior-class>
org.jsf2foo.behavior.confirm.ConfirmBehavior
</behavior-class>
</behavior>
</faces-config>
<faces-config>
<behavior> <behavior-id>jsf2foo.behavior.Confirm</behavior-id>
<behavior-class>
org.jsf2foo.behavior.confirm.ConfirmBehavior
</behavior-class>
</behavior>
</faces-config>
JSF Component Behaviors
Register Behavior: New School
@FacesBehavior("jsf2foo.behavior.Confirm”)
public class ConfirmBehavior …
@FacesBehavior("jsf2foo.behavior.Confirm”)
public class ConfirmBehavior …
JSF Component Behaviors
Step 3: Define the Tag Registering Behavior enables
Application.createBehavior(String) Still need a tag to expose to page authors Facelets tags are defined in taglib.xml file taglib.xml files live in WEB-INF or META-INF
JSF Component Behaviors
Jsf2foo.taglib.xml
<facelet-taglib>
<namespace>http://jsf2foo.org/behavior</namespace> <tag> <tag-name>confirm</tag-name> <behavior> <behavior-id>jsf2foo.behavior.Confirm</behavior-id> </behavior> </tag>
</facelet-taglib>
<facelet-taglib>
<namespace>http://jsf2foo.org/behavior</namespace> <tag> <tag-name>confirm</tag-name> <behavior> <behavior-id>jsf2foo.behavior.Confirm</behavior-id> </behavior> </tag>
</facelet-taglib>
JSF Component Behaviors
Step 4: Ready To Go
The Behavior is now available for use under namespace specified in the taglib.xml file
JSF Component Behaviors
ConfirmBehavior Usage
<html … xmlns:j2f="http://jsf2foo.org/behavior">
…
<h:commandButton value="Submit">
<j2f:confirm/>
</h:commandButton>
<html … xmlns:j2f="http://jsf2foo.org/behavior">
…
<h:commandButton value="Submit">
<j2f:confirm/>
</h:commandButton>
JSF Component Behaviors
What Gets Rendered?
<input type="submit"
value="Submit"
onclick="return confirm('Are you sure?')" />
<input type="submit"
value="Submit"
onclick="return confirm('Are you sure?')" />
JSF Component Behaviors
Behavior API: Advanced Topics
JSF Component Behaviors
ClientBehaviorContext Provides context for getScript()
– FacesContext– Component– Event name– Parameters– Source id
JSF Component Behaviors
ClientBehaviorHints Enum returned by ClientBehavior.getHints() Provides hints to component/renderer Currently only one hint: SUBMITTING
JSF Component Behaviors
ClientBehavior Decoding ClientBehaviors also participate in decoding
– ClientBehavior.decode()
Allows scripts to communicate back to server What can ClientBehaviors do in decode?
– Queue an event– Send a response
JSF Component Behaviors
Server-Side Events ClientBehaviors can queue events Events are queued on parent component Leverage existing FacesEvent lifecycle BehaviorEvent extends FacesEvent BehaviorListener extends FacesListener
JSF Component Behaviors
AjaxBehavior Event Sample
<!-- Don't need a special event here --><h:commandButton actionListener="#{foo.doIt}"> <f:ajax/></h:commandButton>
<!-- But comes in handy here --><h:panelGroup> <foo:showHoverContent event=“mouseover” listener="#{foo.hover}"/></h:panelGroup>
<!-- Don't need a special event here --><h:commandButton actionListener="#{foo.doIt}"> <f:ajax/></h:commandButton>
<!-- But comes in handy here --><h:panelGroup> <foo:showHoverContent event=“mouseover” listener="#{foo.hover}"/></h:panelGroup>
JSF Component Behaviors
Behavior API So far we've been focusing on ClientBehavior API There is more to the story: Behavior API ClientBehavior extends Behavior Base class for other possible non-client Behaviors
– Phased behavior
Behavior defines event handling contract– broadcast(BehaviorEvent)
JSF Component Behaviors
ClientBehaviorRenderer ClientBehaviors can delegate to RenderKit-specific
ClientBehaviorRenderers Similar to UIComponent/Renderer split Allows RenderKit-specific script generation and
decoding Allows frameworks to plug in framework-specific
functionality without replacing ClientBehavior implementations.
JSF Component Behaviors
Auto Suggest Behavior
JSF Component Behaviors
Goals/Assumptions Provide Google Auto Suggest-like functionality Behavior attached to arbitrary input components Assumption: Access to specific client events Assumption: DOM input element
JSF Component Behaviors
Contract
We need an API for retrieving suggestions.
JSF Component Behaviors
Contract: Suggester
public interface Suggester {
public Collection<String> suggest(String prefix);
}
public interface Suggester {
public Collection<String> suggest(String prefix);
}
JSF Component Behaviors
Contract
We need a tag API.
JSF Component Behaviors
Contract: Tag
<!-- Attach to standard inputText -->
<h:inputText id="search">
<j2f:suggest suggester="#{suggester}"/>
</h:inputText>
<!-- Attach to Trinidad inputText too -->
<tr:inputText id="search">
<j2f:suggest suggester="#{suggester}"/>
</tr:inputText>
<!-- Attach to standard inputText -->
<h:inputText id="search">
<j2f:suggest suggester="#{suggester}"/>
</h:inputText>
<!-- Attach to Trinidad inputText too -->
<tr:inputText id="search">
<j2f:suggest suggester="#{suggester}"/>
</tr:inputText>
JSF Component Behaviors
Event Handling Behavior Key events: Retrieve suggestions, show list Up/down arrow: Navigate suggestions list Enter: Accept suggestion Escape: Hide suggestions list Blur: Hide suggestions list
JSF Component Behaviors
Handler Implementation Typically the default BehaviorHandler is sufficient We have special requirements Single Behavior instance, multiple events Solution: Need a custom BehaviorHandler
JSF Component Behaviors
SuggestBehavior: getScript() Typically ClientBehaviors generate a single script We have special requirements SuggestBehavior generates event-specific scripts Solution: ClientBehaviorContext.getEventName()
JSF Component Behaviors
Requesting Suggestions Key up activity triggers suggestions list Suggestions retrieved from server Target the SuggestBehavior instance Solution: Use jsf.ajax.request to implement fetch
JSF Component Behaviors
Requesting Suggestions Key up activity triggers suggestions list Suggestions retrieved from server Target the SuggestBehavior instance Solution: Use jsf.ajax.request to implement fetch
JSF Component Behaviors
Selecting a Suggestion Handle key up for arrow key navigation Enter key accepts current selection However, enter key also submits form Solution: cancel default enter key behavior
JSF Component Behaviors
Resource Dependencies SuggestBehavior requires JavaScript, CSS Dependencies should be transparent to application Solution: Use new ResourceHandler mechanism
JSF Component Behaviors
What's Left? State saving Error handling Request collapsing Autocomplete
JSF Component Behaviors
Future
JSF Component Behaviors
Ideas Targeted postback paylaods Ajax over GET Out of band Ajax Improved Ajax queueing/event collapsing Pre-execute behavior processing Alternate behavior contracts Fallback behavior Attached object value expression support Attached object state saving Initialization/DOM modifiers