RE: XMLHttpRequest integration on WebObjects
RE: XMLHttpRequest integration on WebObjects
- Subject: RE: XMLHttpRequest integration on WebObjects
- From: John Bruce <email@hidden>
- Date: Sun, 23 Oct 2005 15:35:19 +1000
Hi Miguel,
It really depends on what you want to do. The easist way to use AJAX
in WO is via direct actions. You can use the XHR object to call your
direct action and then you can process the response which can be xml,
html, or even a markup such as json. The are a number of toolkits
available which make doing this in Javascript easier. I've had quite a
bit of success with Prototype and it's decendants. This Javascript lib
is used in the Ruby on Rails framework. Other toolkits such as Dojo
are worth a look as well. I've attached some class files for some Ajax
type components I was messing around with which may give you some
ideas to try out. For my autocompletetion component I modified the
Prototype.js file to return the id of the selected item which I set to
be it's primary key.
When you want to use these components inside WOComponents it gets more
complicated. You need to make sure you don't cache AJAX responses
otherwise you will get backtracking errors. Prototype.js adds an AJAX
http header which can be read to determine if it's an AJAX request.
I'm note sure if the files I have attached will work as is but it may
give you some ideas. Basically they are just standard
WODynamicElements which include some ajax modifications. The hyperlink
example is based on the file from Practical WebObjects.
Cheers,
John
On 10/23/05, Miguel Arroz <email@hidden> wrote:
> Hi!
>
> I'm totally lost here, and need a little guidance... I would like
> to integrate XMLHttpRequests on a WebObjects application, so that it
> may be a little "AJAXed". Where do I start? How to integrate
> XMLHttpRequest on the Request-Responde cycle? How to make reusable
> "Ajax" components?
>
> Yours
>
> Miguel Arroz
>
> "We have no sympathy for the lost souls
> We've chosen the path of disgrace
> We give this life to our children
> And teach them to hate this place" -- Apocalyptica, Life Burns!
>
> Miguel Arroz
> http://www.ipragma.com
>
>
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Webobjects-dev mailing list (email@hidden)
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
>
/*
* Created on Jul 27, 2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
import com.webobjects.appserver.*;
import com.webobjects.foundation.*;
/**
* @author john
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class Suggest extends WODynamicElement {
public static final String DIRECT_ACTION_CLASS_NAME_BINDING_KEY = "directActionClassName";
public static final String ACTION_BINDING_KEY = "action";
public static final String PAGE_NAME_BINDING_KEY = "pageName";
public static final String UPDATE_BINDING_KEY = "update";
public static final String INPUT_ID_BINDING_KEY = "id";
public static final String INPUT_NAME_BINDING_KEY = "name";
public static final String OPTIONS_BINDING_KEY = "options";
protected WOAssociation action;
protected WOAssociation directActionClassName;
protected WOAssociation pageName;
protected WOAssociation update;
protected WOAssociation inputId;
protected WOAssociation inputName;
protected NSDictionary extraBindings = null;
protected WOElement children;
protected WOAssociation options;
public Suggest(String name, NSDictionary associations, WOElement children) {
super(name, associations, children);
// TODO Auto-generated constructor stub
action = (WOAssociation)associations.objectForKey(ACTION_BINDING_KEY);
directActionClassName = (WOAssociation)associations.objectForKey(DIRECT_ACTION_CLASS_NAME_BINDING_KEY);
pageName = (WOAssociation)associations.objectForKey(PAGE_NAME_BINDING_KEY);
update = (WOAssociation)associations.objectForKey(UPDATE_BINDING_KEY);
inputId = (WOAssociation)associations.objectForKey(INPUT_ID_BINDING_KEY);
inputName = (WOAssociation)associations.objectForKey(INPUT_NAME_BINDING_KEY);
options = (WOAssociation)associations.objectForKey(OPTIONS_BINDING_KEY);
if (associations.count() > 1)
{
NSMutableDictionary tempBindings = new NSMutableDictionary(associations);
tempBindings.removeObjectForKey(ACTION_BINDING_KEY);
tempBindings.removeObjectForKey(PAGE_NAME_BINDING_KEY);
tempBindings.removeObjectForKey(UPDATE_BINDING_KEY);
tempBindings.removeObjectForKey(INPUT_ID_BINDING_KEY);
tempBindings.removeObjectForKey(INPUT_NAME_BINDING_KEY);
tempBindings.removeObjectForKey(OPTIONS_BINDING_KEY);
extraBindings = tempBindings.immutableClone();
}
this.children = children;
}
public void appendToResponse(WOResponse r, WOContext ctx) {
String updateElement = update != null ? (String)update.valueInComponent(ctx.component()) : (String)inputId.valueInComponent(ctx.component()) + "_auto_complete";
r.appendContentString("<!-- AJAX Suggest Start -->");
r.appendContentString("<input autocomplete=\"off\" id=\"");
r.appendContentString((String)inputId.valueInComponent(ctx.component()));
r.appendContentString("\" name=\"");
r.appendContentString((String)inputName.valueInComponent(ctx.component()));
r.appendContentString("\" size=\"30\" type=\"text\" value=\"\" class=\"text\" />");
r.appendContentString("<div class=\"auto_complete\" id=\"");
r.appendContentString(updateElement);
r.appendContentString("\"></div>");
r.appendContentString("<script type=\"text/javascript\">");
r.appendContentString("new Ajax.Autocompleter('");
r.appendContentString((String)inputId.valueInComponent(ctx.component()));
r.appendContentString("','");
r.appendContentString(updateElement);
r.appendContentString("','");
String daAction = directActionClassName != null ? (String)directActionClassName.valueInComponent(ctx.component()) + "/" + (String)action.valueInComponent(ctx.component()) : (String)action.valueInComponent(ctx.component());
r.appendContentString(ctx.directActionURLForActionNamed(daAction, null));
if (options.valueInComponent(ctx.component()) != null) {
r.appendContentString("', {");
r.appendContentString((String)options.valueInComponent(ctx.component()));
r.appendContentString("});</script>");
} else {
r.appendContentString("', {});</script>");
}
r.appendContentString("<!-- AJAX Suggest End -->");
}
public WOActionResults invokeAction(WORequest aRequest, WOContext aContext) {
WOActionResults result = null;
/*if (aContext.senderID().equals(aContext.elementID()))
{
if (action() != null)
{
// Invoke the bound action. Binding to a method that returns
// null is acceptable.
String searchValue = (String)aRequest.formValueForKey((String)inputName.valueInComponent(aContext.component()));
aContext.component().takeValueForKey(searchValue, "partSearchString");
result = (WOActionResults)action().valueInComponent(aContext.component());
// Substitute aContext().page() for null so that processing stops
if (result == null)
{
result = aContext.page();
}
}
else
{
// Get and validate the page name. Binding to a null page name
// is not acceptable.
String nameInComponent = (String)pageName().valueInComponent(aContext.component());
if (nameInComponent == null)
{
throw new IllegalStateException("<" + getClass().getName() +
"> : Missing page name.");
}
WOComponent responseComponent = WOApplication.application().pageWithName(nameInComponent, aContext);
String searchValue = (String)aRequest.formValueForKey((String)inputName.valueInComponent(aContext.component()));
responseComponent.takeValueForKey(searchValue, "searchString");
aContext.component().takeValueForKey(searchValue, "searchString");
responseComponent.takeValueForKey(aContext.component(), "containingPage");
result = responseComponent;
aContext.response().appendHeader("WO-AJAX","X-Responded-With");
}
}*/
return result;
}
public WOAssociation action() {
return action;
}
public WOAssociation pageName() {
return pageName;
}
public WOElement children() {
return children;
}
public WOAssociation options() {
return options;
}
public NSDictionary extraBindings() {
return extraBindings;
}
}
import java.util.*;
import com.webobjects.appserver.*;
import com.webobjects.appserver._private.*;
import com.webobjects.foundation.*;
/**
* WOHyperlink partial re-implmentation as a WODynamicElement. Only the action
* and pageName bindings are directly supported. Any additional bindings are
* copied.
*
* @author Charles Hill and Sacha Mallais
*/
public class Hyperlink extends WODynamicElement
{
public static final String ACTION_BINDING_KEY = "action";
public static final String PAGE_NAME_BINDING_KEY = "pageName";
public static final String UPDATE_BINDING_KEY = "update";
protected WOAssociation action;
protected WOAssociation pageName;
protected WOAssociation update;
protected NSDictionary extraBindings = null;
protected WOElement children;
/**
* Constructor.
*
* @param name not used
* @param associations bindings from WOD file
* @param children HTML inside link
*/
public Hyperlink(String name, NSDictionary associations, WOElement children)
{
super(name, associations, children);
//System.out.println("Creating AJAX Hyperlink");
/** require [associations_valid] associations != null; **/
action = (WOAssociation)associations.objectForKey(ACTION_BINDING_KEY);
pageName = (WOAssociation)associations.objectForKey(PAGE_NAME_BINDING_KEY);
update = (WOAssociation)associations.objectForKey(UPDATE_BINDING_KEY);
// Binding validation, one is required.
if (action() == null && pageName() == null)
{
throw new WODynamicElementCreationException("<" +
getClass().getName() + "> Missing required attribute: 'action' or 'pageName'");
}
// Binding validation, both are not allowed.
if (action() != null && pageName() != null)
{
throw new WODynamicElementCreationException("<" +
getClass().getName() + "> Must specify only one of: 'action' or 'pageName'");
}
// Usage validation, <a href="..."></a> is not allowed
if (children == null)
{
throw new WODynamicElementCreationException("<" +
getClass().getName() + "> Missing contents. Hyperlink must be " +
"wrapped around something");
}
// Handle extra bindings such as style, class, etc.
if (associations.count() > 1)
{
NSMutableDictionary tempBindings = new NSMutableDictionary(associations);
tempBindings.removeObjectForKey(ACTION_BINDING_KEY);
tempBindings.removeObjectForKey(PAGE_NAME_BINDING_KEY);
tempBindings.removeObjectForKey(UPDATE_BINDING_KEY);
extraBindings = tempBindings.immutableClone();
}
this.children = children;
}
/**
* Add hyperlink to response's content as:<br />
* <code>
* <a href="<i>actionUrl</i>> <i>[optional bindings]><i>children</i></a>
* <code>
*/
public void appendToResponse(WOResponse aResponse, WOContext aContext)
{
// Output <a href="url"
aResponse.appendContentString("<!-- Our Hyperlink -->");
aResponse.appendContentString("<a href=\"#\" onclick=\"new Ajax.Updater('");
aResponse.appendContentString((String)update.valueInComponent(aContext.component()));
aResponse.appendContentString("','");
aResponse.appendContentString(aContext.componentActionURL());
aResponse.appendContentString("', {asynchronous:true, evalScripts:true}); return false;\""); //,onComplete:function(request){displayText(request);}}); return false;\"");
// Output optional bindings
if (extraBindings() != null)
{
Enumeration bindings = extraBindings().keyEnumerator();
String bindingName;
WOAssociation binding;
while (bindings.hasMoreElements())
{
bindingName = (String) bindings.nextElement();
binding = (WOAssociation) extraBindings.objectForKey(bindingName);
aResponse.appendContentString(" ");
aResponse.appendContentString(bindingName);
aResponse.appendContentString("=\"");
aResponse.appendContentString((String)binding.valueInComponent(aContext.component()));
aResponse.appendContentString("\"");
}
}
// Close opening tag
aResponse.appendContentString(">");
// Output text, image, etc. that will be clicked on
children().appendToResponse(aResponse, aContext);
// Output closing tag
aResponse.appendContentString("</a>");
aResponse.appendContentString("<!-- Our Hyperlink End -->");
}
/**
* If this action is directed at us, either invoke the bound action or create
* a new instance of the named page and return the result.
*/
public WOActionResults invokeAction(WORequest aRequest, WOContext aContext)
{
WOActionResults result = null;
if (aContext.senderID().equals(aContext.elementID()))
{
if (action() != null)
{
// Invoke the bound action. Binding to a method that returns
// null is acceptable.
result = (WOActionResults)action().valueInComponent(aContext.component());
// Substitute aContext().page() for null so that processing stops
if (result == null)
{
result = aContext.page();
}
}
else
{
// Get and validate the page name. Binding to a null page name
// is not acceptable.
String nameInComponent = (String)pageName().valueInComponent(aContext.component());
if (nameInComponent == null)
{
throw new IllegalStateException("<" + getClass().getName() +
"> : Missing page name.");
}
result = WOApplication.application().pageWithName(nameInComponent, aContext);
}
}
return result;
/** ensure [result_if_action_invoked] Result != null ||
! aContext.senderID().equals(aContext.elementID());
**/
}
/**
* Returns the WOAssociation for the action this component is bound to, or
* null if pageName is being used.
*
* @return the WOAssociation for the action this component is bound to, or
* null if pageName is being used
*/
public WOAssociation action()
{
return action;
}
/**
* Returns the name of the page this component should return or null if
* action is being used.
*
* @return the name of the page this component should return or null if
* action is being used
*/
public WOAssociation pageName()
{
return pageName;
}
/**
* Returns the WOElement representing the HTML between <a> and </a>
*
* @return the WOElement representing the HTML between <a> and </a>
*/
public WOElement children()
{
return children;
}
/**
* Returns a dictionary of any optional bindings with the key being the
* binging name and the value being the association. These are rendered as
* HTML tags on the <a> element.
*
* @return a dictionary of any optional bindings
*/
public NSDictionary extraBindings()
{
return extraBindings;
}
/** invariant [has_action_or_pageName] action() != null || pageName() != null; **/
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden