JSF Component Behaviors

80
JSF Component Behaviors JSF Component Behaviors Andy Schwartz | Oracle Corporation

description

JSF Summit 2009 presentation covering the JSF 2 component Behavior API.

Transcript of JSF Component Behaviors

Page 1: JSF Component Behaviors

JSF Component Behaviors

JSF Component Behaviors

Andy Schwartz | Oracle Corporation

Page 2: JSF Component Behaviors

JSF Component Behaviors

Agenda History Behavior API: Basics A Simple Sample Behavior Behavior API: Advanced Topics Auto Suggest Sample Behavior Future

Page 3: JSF Component Behaviors

JSF Component Behaviors

History

Page 4: JSF Component Behaviors

JSF Component Behaviors

First First, there was Ajax. And it was good. But it required JavaScript code.

Page 5: JSF Component Behaviors

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

Page 6: JSF Component Behaviors

JSF Component Behaviors

Ajax JavaScript API The Good

– Standard– Flexible

The Bad– Verbose– Error-prone

Page 7: JSF Component Behaviors

JSF Component Behaviors

Time for a declarative Ajax API

Page 8: JSF Component Behaviors

JSF Component Behaviors

Declarative Ajax, Take 1

New Components?

Page 9: JSF Component Behaviors

JSF Component Behaviors

Sample: New Components?

<h:commandButton value=“Not Ajax”/>

<a:commandButton value=“Ajax!”/>

<h:commandButton value=“Not Ajax”/>

<a:commandButton value=“Ajax!”/>

Page 10: JSF Component Behaviors

JSF Component Behaviors

New Components? The Good

– Simple– Familiar

The Bad– Component explosion– Next feature: more components?

Page 11: JSF Component Behaviors

JSF Component Behaviors

Declarative Ajax, Take 2

New Attributes?

Page 12: JSF Component Behaviors

JSF Component Behaviors

Sample: New Attributes?

<h:commandButton ajax=“true”/><h:commandButton ajax=“true”/>

Page 13: JSF Component Behaviors

JSF Component Behaviors

New Attributes? The Good

– Simple– No new components

The Bad– Attribute explosion– Next feature: more attributes?

Page 14: JSF Component Behaviors

JSF Component Behaviors

Declarative Ajax, Take 3

Attached Objects?

Remember those?

Page 15: JSF Component Behaviors

JSF Component Behaviors

What Are Attached Objects?

Attached objects enhance components with functionality not anticipated by the original component author.

Page 16: JSF Component Behaviors

JSF Component Behaviors

Some Existing Attached Objects Converters

– f:convertNumber– f:convertDateTime

Validators– f:validateLength– f:validateBean– f:validateRegex

Page 17: JSF Component Behaviors

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>

Page 18: JSF Component Behaviors

JSF Component Behaviors

Ajax Attached Object

Yes!

Page 19: JSF Component Behaviors

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!

Page 20: JSF Component Behaviors

JSF Component Behaviors

Behavior API: Basics

Page 21: JSF Component Behaviors

JSF Component Behaviors

API Requirements

Loose Coupling

Surprise?

Page 22: JSF Component Behaviors

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

Page 23: JSF Component Behaviors

JSF Component Behaviors

Two New Contracts

ClientBehavior ClientBehaviorHolder

Page 24: JSF Component Behaviors

JSF Component Behaviors

ClientBehavior Contract

String getScript(ClientBehaviorContext)

Page 25: JSF Component Behaviors

JSF Component Behaviors

ClientBehavior Scripts

What can a ClientBehavior script do?

Page 26: JSF Component Behaviors

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!’)”; }

Page 27: JSF Component Behaviors

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)”; }

Page 28: JSF Component Behaviors

JSF Component Behaviors

What Else? Client-side validation DOM manipulation Tooltips, hover content Disclosures Logging Confirmation Key handling Auto-suggest

Page 29: JSF Component Behaviors

JSF Component Behaviors

Who Calls getScript()?

Components/Renderers call getScript() during rendering and insert scripts into the generated markup.

Page 30: JSF Component Behaviors

JSF Component Behaviors

Standard ClientBehaviors Just one for now

– Java API: AjaxBehavior– Tag API: <f:ajax>

Page 31: JSF Component Behaviors

JSF Component Behaviors

Attaching ClientBehaviors

Remember EditableValueHolder?

Page 32: JSF Component Behaviors

JSF Component Behaviors

ClientBehaviorHolder Contract

void addClientBehavior(

String eventName,

ClientBehavior behavior)

void addClientBehavior(

String eventName,

ClientBehavior behavior)

Page 33: JSF Component Behaviors

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

Page 34: JSF Component Behaviors

JSF Component Behaviors

ClientBehaviorHolder Contract

Collection<String> getEventNames();Collection<String> getEventNames();

Page 35: JSF Component Behaviors

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>

Page 36: JSF Component Behaviors

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

Page 37: JSF Component Behaviors

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>

Page 38: JSF Component Behaviors

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>

Page 39: JSF Component Behaviors

JSF Component Behaviors

Default Events

What happens if you do not specify an event?

Page 40: JSF Component Behaviors

JSF Component Behaviors

ClientBehaviorHolder Contract

String getDefaultEventName();String getDefaultEventName();

Page 41: JSF Component Behaviors

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>

Page 42: JSF Component Behaviors

JSF Component Behaviors

More Event Fun: Chaining

<h:commandButton> <foo:confirm/> <f:ajax/></h:commandButton>

<h:commandButton> <foo:confirm/> <f:ajax/></h:commandButton>

Page 43: JSF Component Behaviors

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>

Page 44: JSF Component Behaviors

JSF Component Behaviors

Standard ClientBehaviorHolders

All standard components implement ClientBehaviorHolder.

Page 45: JSF Component Behaviors

JSF Component Behaviors

A Simple Sample Behavior

Page 46: JSF Component Behaviors

JSF Component Behaviors

Our Simple Sample Behavior

Confirm Behavior

Page 47: JSF Component Behaviors

JSF Component Behaviors

Step 1: Implement the Behavior Extend ClientBehaviorBase Implement getScript()

Page 48: JSF Component Behaviors

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?')";

}

}

Page 49: JSF Component Behaviors

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)

Page 50: JSF Component Behaviors

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>

Page 51: JSF Component Behaviors

JSF Component Behaviors

Register Behavior: New School

@FacesBehavior("jsf2foo.behavior.Confirm”)

public class ConfirmBehavior …

@FacesBehavior("jsf2foo.behavior.Confirm”)

public class ConfirmBehavior …

Page 52: JSF Component Behaviors

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

Page 53: JSF Component Behaviors

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>

Page 54: JSF Component Behaviors

JSF Component Behaviors

Step 4: Ready To Go

The Behavior is now available for use under namespace specified in the taglib.xml file

Page 55: JSF Component Behaviors

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>

Page 56: JSF Component Behaviors

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?')" />

Page 57: JSF Component Behaviors

JSF Component Behaviors

Behavior API: Advanced Topics

Page 58: JSF Component Behaviors

JSF Component Behaviors

ClientBehaviorContext Provides context for getScript()

– FacesContext– Component– Event name– Parameters– Source id

Page 59: JSF Component Behaviors

JSF Component Behaviors

ClientBehaviorHints Enum returned by ClientBehavior.getHints() Provides hints to component/renderer Currently only one hint: SUBMITTING

Page 60: JSF Component Behaviors

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

Page 61: JSF Component Behaviors

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

Page 62: JSF Component Behaviors

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>

Page 63: JSF Component Behaviors

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)

Page 64: JSF Component Behaviors

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.

Page 65: JSF Component Behaviors

JSF Component Behaviors

Auto Suggest Behavior

Page 66: JSF Component Behaviors

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

Page 67: JSF Component Behaviors

JSF Component Behaviors

Contract

We need an API for retrieving suggestions.

Page 68: JSF Component Behaviors

JSF Component Behaviors

Contract: Suggester

public interface Suggester {

public Collection<String> suggest(String prefix);

}

public interface Suggester {

public Collection<String> suggest(String prefix);

}

Page 69: JSF Component Behaviors

JSF Component Behaviors

Contract

We need a tag API.

Page 70: JSF Component Behaviors

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>

Page 71: JSF Component Behaviors

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

Page 72: JSF Component Behaviors

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

Page 73: JSF Component Behaviors

JSF Component Behaviors

SuggestBehavior: getScript() Typically ClientBehaviors generate a single script We have special requirements SuggestBehavior generates event-specific scripts Solution: ClientBehaviorContext.getEventName()

Page 74: JSF Component Behaviors

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

Page 75: JSF Component Behaviors

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

Page 76: JSF Component Behaviors

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

Page 77: JSF Component Behaviors

JSF Component Behaviors

Resource Dependencies SuggestBehavior requires JavaScript, CSS Dependencies should be transparent to application Solution: Use new ResourceHandler mechanism

Page 78: JSF Component Behaviors

JSF Component Behaviors

What's Left? State saving Error handling Request collapsing Autocomplete

Page 79: JSF Component Behaviors

JSF Component Behaviors

Future

Page 80: JSF Component Behaviors

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