My use of AJAX technology in existing applications has been mostly minor. For the most part I don't believe that AJAX is a way to replace the existing Web application metaphor unlike some of the mongors of hype machine might have us believe. I see AJAX Callback technology primarily as 'Icing on the Cake' for existing Web applications as friend of mine recently commented. In this respect I've had lots of small but very useful enhancements in my applications that work through inline callbacks and make applications more user friendly and responsive, without going overboard.
Here's one use of Callbacks for doing server side field validation from the client and displaying alerts with a JavaScript Tooltip function: An easy way to popup a tooltip type message on or next to a specific control. This comes in handy for a number of things related to callbacks such as providing a quick indicator that data is being updated for example. Something along the lines of this plain HTML:
<input id="btnGetCustomerList" type="button" value="Load"
onclick="ShowToolTip('lstCustomerList','Updating...',0); LookupPanel.GetCustomerList(GetCustomerList_Callback);"
and then on the callback result in JavaScript:
function GetCustomerList_Callback(Result)
{
HideToolTip('lstCustomerList');
// … normal processing code
}
This gives a visual clue to the user that something is happening with the control that is focused directly at the target of the operation.
I also find this ToolTip function useful in validation scenarios for callbacks, which is one of the most useful uses of AJAX in existing applications in my opinion. For example, imagine that you're entering new Inventory data into a form, and you let the user enter a new SKU for the item – you can go out to the server and check to make sure that the SKU doesn't already exist and immediately let the user know that the SKU already exists.
You can do something like this (this uses my wwHoverPanel control and JSON method callbacks, but you can apply this sort of thing to Anthem, Ajax.NET etc. or ATLAS easily).
Control code in ASP.NET script:
<ww:wwwebtextbox onkeyup="UpperCase(this);" id="txtsku" runat="server"
errormessagelocation="RedTextAndIconBelow"
bindingsource="Item.DataRow" bindingsourcemember="sku"
onblur="CheckForDuplicateSku();">
And then handle the inline Server Callback with JavaScript:
function CheckForDuplicateSku()
{
if ($('txtIsNewItem').value == "False")
return;
ItemCallback.SkuExists( $('txtsku').value, SkuExistsCallback );
}
function SkuExistsCallback(Result)
{
if (Result.IsCallbackError)
return;
if (Result == true)
ShowToolTip("txtsku","The sku " + $('txtsku').value + " exists already.",2000,"Mouse");
}
This code calls back to the server to check if the Sku exists already and in this case the result of the server side Page method simply returns true or false. If true the ToolTip is displayed.
This is a very simple and useful way to integrate AJAX functionality into existing applications providing some interactive validation to the page.
You can check this out by going to:
http://www.west-wind.com/webstoreSandbox/admin/EditInventoryItem.aspx
and entering a SKU or description that already exists. Try using WCONNECT or WWHELP40 to see the validation kick in.
Note the use of the tooltip is an easy way to display the information in a somewhat non-intrusive way. While I want to display information to the user I don't really want to stop him from going on with the form. A duplicate SKU may not be valid, but the user may decide to put the sku in very last after everything else has been entered – I hate input forms that don't let you move forward. Server side this is usually done with Validators and I suppose you could also show the message on a validator, but using this tooltip is a little more generic and easier to work, as well as differentiating the message a notification rather than a warning per se.
Remember that if you validate on the client you should still re-validate on the server when or if the page is submitted, or if the data is posted back via a separate callback.
I'm a big believer in keeping things simple and providing incremental functionality and this is one of those little things that makes life easy. It's nothing fancy, but I often find that the least fancy things tend to be the things that are often the most useful in day to day operations.
FWIW, this Inventory page has a couple of more callbacks - another validation for the Description and the Abstract generation, which goes back to the server to format an abstract or can automatically create abstracts for all inventory items that don't already have an abstract defined.
Ok, so here is the little JavaScript ShowToolTip function that I extracted from the wwHoverPanel.js control library. The function has a few nice features like support for the drop shadow, and the ability to automatically timeout. Note that the behavior isn't really exactly like a tool tip as it doesn't pop up on the mouse position but rather at a position you specify (BottomLeft, BottomRight, TopLeft, Mouse). Note that Mouse only works if an event object is active in the call you're making – if not the default goes to BottomLeft.
I also stole ATLAS's shortcut for document.getElementById which is a $() function <g>.
function $(ElementId)
{
return document.getElementById(ElementId);
}
function ShowToolTip(ControlId,Message,Timeout,Position)
{
var Ctl = $(ControlId);
if (Ctl == null)
return;
var ToolTip = $(ControlId + "_ToolTip")
var Shadow = $(ControlId + "_ToolTipShadow")
var Added = false;
if ( Shadow == null)
Shadow = document.createElement('div');
if ( ToolTip == null)
{
ToolTip = document.createElement('div');
Ctl.parentNode.appendChild(Shadow);
Ctl.parentNode.appendChild(ToolTip);
}
if ( Position == null)
Position = "BottomLeft";
var Style=ToolTip.style;
var Style2=Shadow.style;
Style.display = '';
Style2.display = '';
Style.width='';
Style.height='';
ToolTip.id = ControlId + "_ToolTip";
Style.background = "cornsilk";
Style.color = "black";
Style.borderWidth="1px";
Style.borderStyle="solid";
Style.borderColor="gray";
Style.padding="2";
Style.fontSize = "8pt";
Style.fontWeight = "normal";
var OldPosition=Ctl.style.position;
Ctl.style.position = "absolute";
ToolTip.innerHTML = Message;
Style.position = "absolute";
var Left = Ctl.offsetLeft + 10;
var Top = Ctl.offsetTop + Ctl.offsetHeight - 5;
if( Position == "BottomRight")
{
Left = Ctl.offsetLeft + Ctl.offsetWidth - 10;
Top = Ctl.offsetTop + Ctl.offsetHeight - 5;
}
else if (Position == "TopLeft")
{
Left = Ctl.offsetLeft + 2;
Top = Ctl.offsetTop + 2;
}
else if( Position == "Mouse")
{
if (window.event)
{
Left = window.event.clientX;
Top = window.event.clientY;
}
}
var Width = ToolTip.offsetWidth + 2; // Message.length * 6.5;
if (Width > 400)
Width=400;
Style.left = Left + "px";
Style.top = Top + "px";
Style.width= Width + "px";
Shadow.id = ControlId + "_ToolTipShadow";
Style2.position = "absolute";
Style2.background = "silver";
Style2.left = Left + 2 + "px";
Style2.top = Top + 2 + "px";
Style2.width = ToolTip.offsetWidth + "px";
Style2.height = ToolTip.offsetHeight + "px";
Ctl.style.position = OldPosition;
if (Timeout && Timeout > 0)
window.setTimeout("HideToolTip('" + ControlId + "');",Timeout);
}
function HideToolTip(ControlId)
{
var Ctl = $(ControlId + "_ToolTip");
if (Ctl == null)
return;
Ctl.style.display="none";
Ctl = $(ControlId + "_ToolTipShadow").style.display="none";
}
It's interesting how messy even a simple thing like this is. For example, it's crucially important to set the visibility and positioning styles at the right time to get the tooltip to automatically size itself correctly (and IE doesn't quite work right for this as is on repeated invokations).
Anyway, I hope some of you may find this useful.