PPT slides

23
Developing AJAX Web applications with Castle Monorail David De Florinier Gojko Adzic ([email protected]) Skills Matter 12/06/08

description

 

Transcript of PPT slides

Page 1: PPT slides

Developing AJAX Web applications with Castle Monorail

David De FlorinierGojko Adzic ([email protected])

Skills Matter12/06/08

Page 2: PPT slides

Why Monorail for Ajax Apps?

Plumbing handled by the framework Lots of helpers Integrated with Prototype and Scriptaculous

Benefits from Castle Project integrations

Page 3: PPT slides

Write AJAX apps without much more

code than if you were writing a non-ajax one!

Page 4: PPT slides

Options for AJAX with Monorail Preparing the application Proxying calls Monorail helpers and effects How it all comes together Some best practices and pitfalls

Page 5: PPT slides

Option #1: Rails-style JS Generator

Ajax actions send commands to the page

Use NJS views instead of VM for Ajax Actions

Mix and match Ajax and Non-Ajax calls

Reuse partial templates

Page 6: PPT slides

Option #2: Use Prototype and build parts of the page with

actions

Ajax actions build only parts of the page Use AjaxHelper to coordinate calls Coordinate page updates from the browser side Cleaner code on the server, more focused Option to use JSONHelper to render results Option to use controller proxies

Page 7: PPT slides

Option #3: “Transparent” JSON controller binding

Actions exported to the web page Coordinate rendering on the client Clean code, all plumbing done by MR Use JSonReturnBinder and

JSonBinder ... but not yet complete

Page 8: PPT slides

Preparing the application for AJAX

Add prototype.js library

$AjaxHelper.GetJavascriptFunctions()

... will render ...

<script type="text/javascript"

src="/MonoRail/Files/AjaxScripts.rails">

</script> Use Ajax.Request and Ajax.Updater

Page 9: PPT slides

Use AjaxHelper to create elements

$AjaxHelper.ButtonToRemote("Delete", "DeleteHero.rails", "%{ Complete='heroActionCallback(request)' , with='\'id=${item.Id}\'' }")

... will render ...

<input type="button" value="Delete" onclick="new Ajax.Request('DeleteHero.rails', {onComplete:function(request) { heroActionCallback(request) } , asynchronous:true, evalScripts:true, parameters:'id=3'}); return false;"/>

Methods provided for links, buttons, observers, autocompletion, forms

Page 10: PPT slides

Use AjaxHelper to Build Forms

$AjaxHelper.BuildFormRemoteTag("/Heroes/CreateHero.rails", "%{update='heroList',formid='heroForm', Complete='document.pageHelper.heroes.listRefreshed();'}")

... will render ...

<form id="heroForm" method="post" action="/Heroes/CreateHero.rails" enctype="multipart/form-data" onsubmit="new Ajax.Updater('heroList', '/Heroes/CreateHero.rails', {onComplete:function(request) { document.pageHelper.heroes.listRefreshed(); } , asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">

Page 11: PPT slides

AjaxHelper parameters

with form update success/failure evalScripts complete onSuccess/onFailure before/after/condition

Page 12: PPT slides

Preparing controllers for AJAX

Implemented as a method on the controller Tightly focused

Promotes reusability Reduces risk due to change Simplifies unit tests

Page 13: PPT slides

Generating controller proxies Decorate methods with AjaxAction attribute[AjaxAction]

public void DeleteHero(int id) {}

Use AjaxHelper.GenerateJSProxy$AjaxHelper.GenerateJSProxy("controllerProxy")

.. then the following is rendered

var controllerProxy =

{

deleteHero: function(id, callback) {

var r=new Ajax.Request('/Heroes/DeleteHero.rails', {method: 'get', asynchronous: !!callback, onComplete: callback, parameters: '_=\x26id='+id+''});

if(!callback) return r.transport.responseText;

}

};

Page 14: PPT slides

Synchronous / asynchronous calls Proxies allow both synchronous and

asynchronous calls to be made Supply a callback function to make

asynchronous callfunction heroActionCallback(result) {

var response = result.responseText.evalJSON();

alert(response.message);

}

function deleteHero(id) {

controllerProxy.deleteHero( id, heroActionCallback);

}

Page 15: PPT slides

Synchronous / asynchronous calls

Use synchronous calls ONLY if you don't want anything else to happen

Prefer async calls for better performance Async replies can come in different order Number of simultaneous calls to the same

domain is very limited

Page 16: PPT slides

Monorail layout strategies

Monorail has a concept of layouts AJAX actions would not have a layout

... but index method would There is more than one way to achieve this Two methods illustrated NJS templates don't use layouts (JS

Generation)

Page 17: PPT slides

AJAX layout strategy #1

No layout on the class Index method has a layout [Layout("default")]

public void Index()

Simple, quick, no additional code ... but ties the action to blank layout for all calls

Page 18: PPT slides

AJAX layout strategy #2

Use filter to kill layout on AJAX calls public class AjaxLayoutFilter : IFilter {

public bool Perform(ExecuteEnum exec, IRailsEngineContext context, Controller controller) {

if(IsAjaxRequest(context)) controller.CancelLayout();

return true;

} //from http://blechie.com/

public static bool IsAjaxRequest(IRailsEngineContext context) {

string requestedWith = context.Request.Headers["X-Requested-With"];

if (string.IsNullOrEmpty(requestedWith)) return false;

return requestedWith.Equals("XMLHttpRequest",StringComparison.InvariantCultureIgnoreCase);

}

}

Page 19: PPT slides

Script.aculo.us integration

A JavaScript framework which is for UI sugar. Install scripts using

$ScriptaculousHelper.InstallScripts() Add effects using the ScriptaculousHelper

VisualEffect method<script type="text/javascript" >

$ScriptaculousHelper.VisualEffect('ToggleBlind', 'colOne')

$ScriptaculousHelper.VisualEffect('ToggleAppear', 'colThree')

$ScriptaculousHelper.VisualEffect('ToggleBlind', 'colTwo')

</script>

Page 20: PPT slides

Script.aculo.us Drag & Drop

Make elements draggable

new Draggable(element, {revert:true}); Make elements Drop zones

Droppables.add( element, {hoverclass: 'dropHover', accept: 'dropelementclassname', onDrop: dropPower} );

Drop delegate accepts both elements as parameters

function dropPower(draggable,droparea)

Page 21: PPT slides

Stuff to remember

JSON binding will probably be complete soon Use $context for generic shared templates Use $AjaxHelper for Prototype integration Use $ScriptaculousHelper for effects You can use Prototype and Scriptaculous in JS

code directly Use async calls for better performance

Page 22: PPT slides

... a few links

http://www.castleproject.org/MonoRail http://hammett.castleproject.org http://www.ayende.com/blog http://www.prototypejs.org http://script.aculo.us

Page 23: PPT slides

What next?

Beers – straight away ALT.NET meeting next week TDD with Databases in two weeks ALT.NET talk at Skills Matter on July 31st