JSF Component Behaviors

Post on 27-Jan-2015

116 views 7 download

Tags:

description

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

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