ajaxed.callback
, this JavaScript function is our god when it comes to AJAX usage. It's usage can be simple but also very complex. A detailed explanation of its parameters and the usage follows below.
If you are starting to use ajaxed, please refer to the beginners tutorials first. This article requires advanced ajaxed and JavaScript knowledge.
First of all you should know that
ajaxed.callback
has to be used if you want to use ajaxed Page Parts or want to call server side functions. It's the communication node between client side and server side.
Now let's take a look at the method signature:
ajaxed.callback(action, onReturn, [params, onCompleted, url])
- action: The action which is called on server side. If there is a server side procedure named after the action e.g.
pagepart_yourActionName
then the procedure is being called directly. Otherwise callback
is executed and the action is passed as the argument. - onReturn: Reference to a JavaScript function which will handle the returned values from server side. In case of a page part you can specify the ID of the target element.
- params (optional): Parameters for the action in JSON notation. Those parameters are sent as POST parameters to the server. Thus they are accessible through the
request.form
collection on server side. - onCompleted (optional): Reference to a JavaScript function which will be executed when the action has completed (even if it failed).
- url (optional): The url where the action is located. By default its the URL of the current page. This allows you to call actions which are located within other pages.
Okay, thats the theoretical part. Lets get some examples done. I want to demonstrate all the different usage scenarios. Read carefully as it can get a bit tricky sometimes.
Using the action
The action is being used to identify the callback on the server side. This allows you to add as many callback as you want. Basically every action is piped into our
callback
procedure unless it finds a procedure with the same name and prefixed with
pagepart_
. In this case it calls the procedure directly and returns its response back to the client
<%
sub callback(a)
if a = "one" then
'NEVER REACHED! because there is a
'sub called pagePart_one
page.return "foo"
elseif a = "two" then
'will be reached
page.return "foo"
end if
end sub
sub pagePart_one
str.write("<strong>some html response</strong>")
end sub
%>
<script>
ajaxed.callback("one", function(r) {
//do something
});
ajaxed.callback("two", function(r) {
//do something
});
</script>
Using the onReturn
The function passed to the
onReturn
parameter will be invoked once the callback has been finished successfully. It's NEVER called if something fails as opposed to the
onComplete
function.
Be sure to provide one parameter for it. This parameter will hold the response back from the server. In case of a callback it contains all the variables sent with
AjaxedPage.return()
or
AjaxedPage.returnValue()
. In case of a page part call it contains a string which holds the XHTML produced by the page part.
<%
sub callback(a)
if a = "actionOne" then
page.return "wow!"
end if
end sub
sub pagePart_partOne %>
<strong>hi</strong>
<% end sub %>
<script>
//you can create functions and reuse them
function myHandler(r) {
alert(r);
}
//will alert "<strong>hi</strong>"
ajaxed.callback('partOne', myHandler);
//will alert "wow!"
ajaxed.callback('actionOne', myHandler);
//you can write the function inline as well
//will alert "wow!"
ajaxed.callback('actionOne', function(r) {
alert(r)
});
</script>
And because we want to make life easier for developers you can also pass a string in case of a page part. Then the string is treated as the ID of the target element. This element will be updated with the page part response then.
<% sub pagePart_partOne %>
<strong>hi</strong>
<% end sub %>
<script>
ajaxed.callback('partOne', 'destination');
//same, but not rapid :)
ajaxed.callback('partOne', function(r) {
$('destination').update(r)
});
</script>
<div id="destination"></div>
Using parameters
The third parameter of ajaxed.callback can be used to pass parameters to our server side action. By default it checks if there is a form with an ID
frm
. If there is one it grabs all its form fields and passes those values as parameters to your action. If ther is no form called
frm
then no parameters are being sent unless you specify them manually. You can always provide the parameters by yourself regardless of an existing form or not. Those parameters must be provided as a
Hash then (name value pairs in JSON notation). All parameters are available via the
request.form
collection on the server side afterwards.
<script>
//#1
//will automatically pass the param1 value
//to the server side (because the page contains
//a form with the ID 'frm'
ajaxed.callback('check', function(r) {
//do something
});
//#2
//provide parameters manually
ajaxed.callback('check', function(r) {
//do something
}, {someParam1: "foo", anotherParam: "foo"});
//#3
//take parameter from form and add an own (1st)
ajaxed.callback('check', function(r) {
//do something
}, {pName: $F("pID"), anotherParam: "foo"});
//#4
//take parameter from form and add an own
//automatically grab all fields from the form
ajaxed.callback('check', function(r) {
//do something
}, $("frm").serialize(true).set(anotherParam, "foo"));
</script>
<form id="frm">
<input type="text" id="pID" name="pName" value="foo"/>
</form>
<%
'our server side handler
sub callback(a)
if a <> "check" then exit sub
'will contain "foo" when calling with #1, #2, #4
'will contain no value when caling with #3
pName = page.RF("pname")
'will contain value only when calling with #3
someParam1 = page.RF("someParam1")
'will always contain "foo" unless on #1 call
anotherParam = page.RF("anotherParam")
end sub
%>
All this applies to page parts and callbacks.
Remember: The fields NAME is being used as the parameter name.
Not the fields ID (see in example #3)!
You can pass parameters the same way to a page part. You can access the parameter afterwards within the page part. Check the following example:
<!--#include virtual="/ajaxed/ajaxed.asp"-->
<%
set page = new AjaxedPage
page.draw()
sub main() %>
<div id="output"><% pagePart_one %></div>
<form id="frm" onsubmit="ajaxed.callback('one', 'output'); return false">
<input type="text" name="value">
<input type="submit" value="send">
</form>
<% end sub %>
<% sub pagePart_one %>
You typed: <%= page.RF("value") %>
<% end sub %>
Run this code — pagepart_param.asp
Using onCompleted
The
onCompleted
parameter can hold a reference to a JavaScript function which is invoked after the callback has completed (its being passed the
XMLHttpRequest
object). Very useful to do clean up work. Check the following example. It demonstrated how to disable a button on callback and enable it back again when it finished.
<%
sub callback(a)
if a = "myAction" then page.return "something"
end sub
%>
<script>
function doFoo(sender) {
//first we disable our element which invokes
//the function. So he cannot call it again as
//as its already running
Field.disable(sender);
ajaxed.callback('myAction', function(r) {
//do something
}, null, function(t) {
//when the callback completes we enable it back
Field.enable(sender)
})
}
</script>
<button type="button" onclick="doFoo()">Do</button>
You have to place the enable code into the onComplete as it would never enable the button when the action failed.
Using the url parameter
This parameter tells us where the server side code is located. By default its the current executing page and this is the most needed case. But sometimes (when it gets tough) you might want to call code within another page (try to avoid it as it reduces readability and maintainability!) or you want to expose a public interface for your application. Read on :)
Important: You need to specify the URL parameter when using ajaxed.callback on a default page of a folder. This is due to a bug within IIS. It does not return the default page when being called (with POST) without the filename.
E.g. Lets say /pages/default.asp is the default page of the /pages/ folder. In that case the ajaxed.callback wont work with only on /pages/
You need to specify default.asp
as the url here. Don't forget the querystring if required.
Being able to specify the URL for the callback you could realize something like services for your application. Every application could expose a file with possible actions and other applications (clients) could call those function and get structured data back (even from outside through the internet). Check this example.
App 1 - file: service.asp
<%
sub callback(a)
'gets the total sales for a given year
if a = "getTotalSales" then
'calculate the total sales somehow
page.return getTotals(page.RFP("yr", 0))
end if
end sub
%>
App 2 - can request the sales from App 1
<script>
ajaxed.callback('getTotalSales', function(r) {
$('sales').update(r);
}, {yr: <%= year(now) %>>);
</script>
Sales this year:
<div id="sales"></div>
Do you see the benefit? You could write complete APIs for your applications. As these calls return JSON it would be possible for other systems (PHP, Java, Ruby, etc.) to consume those APIs. Use your imagination :)
Closing words
As you can see ajaxed.callback is really powerful and allows you to do all kind of tricky calls. To use all its power be sure to understand the basics first. After that you will see how easy it is to hook up AJAX functionality into your apps.
Have fun
Michal