Freitag, Dezember 08, 2006

Building JavaScript Behaviors

During the last months I got some good feedback from readers and friends that point me to some missing topics in my AJAX book. I will continue to publish new content here before bringing a new version of the book.

This is a step by step instruction for building a new ASP.NET Control with a rich client side functionality by using JavaScript and a Behavior mechanism.

The sample functionality I use to show this is a simple dice (German: Würfel). It's a sample that I also used in my session at the "AJAX in Action" Conference in Germany some weeks ago.

You can download all files from http://www.mathertel.de/Downloads/Start_JSBTutorial.aspx.

1. Coding it all in one place

The best place for writing a new control is inside a single HTML file that contains all the fragments that you will separate later into different locations:

  • a HTML object structure that will be used for rendering the new control. This should be a single outer element that may contain complex inner HTML elements. Give it a unique id that can be used to identify the first prototype.
  • a CSS section inside the <head> element that will hold all the style rules that we will later move out into the common css file. You can code all the css rules into the html elements first if you like. Later you should not include any CSS code inside the rendered html elements mo make some personalization and style adoption easier.
  • a <script type="text/javascript"> element that will contain the JavaScript behavior definition using a object notation in the JSON coding style and the statement for binding the JavaScript behavior object to the HTML element.
  • include the common behavior loading mechanism <script type="text/javascript" src="../controls/jcl.js"></script> in the <head> element.

The advantage of using this intermediate development state is that you can hit F5 in the browser and can be sure that all your code will reload as expected. You also will not have any timing problems that may happen when JavaScript or CSS files are cached locally. You need no server side functionality so a *.htm file is fine for now.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <title>Ein Wuerfel</title>
  <script type="text/javascript" src="jcl.js"></script>

  <style type="text/css">
    .Wuerfel {
      border: solid 2px green; width:40px; height:40px; overflow:hidden;
      cursor: pointer; background-color:#EEFFEE;
      font-size: 30px; padding:20px; text-align: center;
    }
  </style>

  <script type="text/javascript">
    var WuerfelBehaviour = {
      onclick: function(evt) {
        Wuerfel1.innerText = Math.floor(Math.random()*6)+1;
      }
    } // WuerfelBehaviour
  </script>
</head>

<body>
  <div id="Wuerfel1" class="Wuerfel" unselectable="on">click</div>
 
  <script defer="defer" type="text/javascript">
    jcl.LoadBehaviour("Wuerfel1", WuerfelBehaviour);
  </script>
</body>
</html>

The file wuerfel_01.htm contains an implementation in this state.

2. replacing all hard-coded references

If you want to make it possible to use the same control multiple times on the same page then you must avoid using hard coded ids or names. The only place where you should find the id of the outer HTML element is inside the first parameter of the jcl.LoadBehaviour function call.

All the other references should be replaced by using the "this" reference.

The other thing you should take care too are the parameters / attributes that you want to use together with the new control. You should define the as attributes in the outer HTML element and as properties of the JavaScript behavior definition. There should not be any constants inside the JSON object.

If everything is well done you can make a second copy of the outer HTML element with a new id and can bind the same behavior definition to it. Both elements should now work as expected independently. Check also if the parameters work as expected.

The file wuerfel_02.htm contains an implementation in this state.

3. separating the behavior code

The next step is to extract the core of the behavior into a new *.js file and reference this file by using a new <script type="text/javascript" src="wuerfel.js"></script> in the <head> element.

The advantage of a separate file for the behavior definition is that the implementation can be cached by the browser independently from the individual use and If the control is reused in different pages you can see dramatic performance improvements.

The file wuerfel_03.htm and wuerfel.js file contain an implementation in this state and wuerfel.js ??? has also got some more functionality.

4. separating the CSS style definitions

The style of the new control should not be coded inline into the html code but should be separated into some css statements. So I use a classname for the top element of the control by using the name of the behavior. If you have special inner elements they can be prefixed by the same name or you might use css selectors by specifying the outer and inner class names. Sample:

div.TreeView .do { ... }
div.TreeView .dc { ... }

Because the css statements are usually much smaller then the JavaScript code for a control I do not extract the css statements into separate files but include them all in a single css file for all the controls I've done. The *.css files are cached by the browser so loading them from the server doesn't occur too often.

5. converting to a ASP.NET User Control (*.ascx)

Now it's time to switch from a *.htm file to a *.aspx file because you will need some server side functionality now.

Rename the file and add a <%@ Page Language="C#" %> statement at the top of the page. In Visual Studio you will have to close the file and reopen it to get the full editor support for the right server side languages.

The html code and the javascript statement that binds the JavaScript Behavior of the new control is copied into the new User Control file wuerfel.ascx.

The id attribute that is rendered for the client should not be hardcoded to a static value. The UniqueID can be used and will produce the given id if one is specified in the *.aspx page.

<div id="<%=this.ClientID
    %>" class="Wuerfel" unselectable="on">click</div>
<script defer="defer" type="text/javascript">
  jcl.LoadBehaviour("<%=this.ClientID %>", WuerfelBehaviour);
</script>

Now it is easy to include the new control into the page by dragging the wuerfel.ascx file into a blank page while using the Design mode. The code will look like this:

<uc1:Wuerfel ID="Wuerfel1" runat="server" />

and a reference to the used control will also be generated:

<%@ Register Src="Wuerfel.ascx" TagName="Wuerfel" TagPrefix="uc1" %>

Open this file by using the browser and have a look to the source code that is delivered to the client - it will look very similar to what you had before. Again you can check whether everything is fine by pasting the <uc1:Wuerfel...> element several times. Visual Studio will automatically generate different ids so all elements work independent.

6. using the script including mechanism

You still have to take care of including the right JavaScript include in the <head> of your page. Now we also get this work done automatically. The advantage is that you do not have to take care of using the right include files and you will never forget to remove them when a control is removed from the page.

In the *.aspx page the <head> element must be marked with runat="server"

In the *.ascx file some server side programming is needed inside a <script runat="server"> tag:

protected override void OnPreRender(EventArgs e) {
  base.OnPreRender(e);

  if (Page.Header == null)
    throw new Exception("The <head> element of this page is not marked with
      runat='server'.");

  // register the JavaScripts includes without need for
    a Form.
  if (!Page.ClientScript.IsClientScriptBlockRegistered(Page.GetType(), "CommonBehaviour")) {
    Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "CommonBehaviour", String.Empty);
    ((HtmlHead)Page.Header).Controls.Add(new LiteralControl("<script type='text/javascript' src='"
      + Page.ResolveUrl("jcl.js")
      + "'><" + "/script>\n"));
  } // if

  if (!Page.ClientScript.IsClientScriptBlockRegistered(this.GetType(), "MyBehaviour")) {
    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "MyBehaviour", String.Empty);
    ((HtmlHead)Page.Header).Controls.Add(new LiteralControl("<script type='text/javascript' src='"
      + Page.ResolveUrl("Wuerfel.js")
      + "'><" + "/script>\n"));
  } // if
} // OnPreRender

Have a look at the files wuerfel_04.aspx and wuerfel.ascx.

7. using a global registration for the control

When dragging a User Control onto a page the UserControl is registered for this page by using a server site Register tag.

<%@ Register Src="Wuerfel.ascx" TagName="Wuerfel" TagPrefix="uc1" %>

There is no real problem with that automatic stuff but if you copy HTML code around from one page to another you always have to take care of copying these Register tags as well.

Fortunately there is another solution that registers User Contols globally in the web.config file and needs no Register tags.

Open the web.config file you can find in the root of your web application and locate the <configuration><system.web><pages><controls> region. Here you can add a add element:

<add src="~/controls/LightBox.ascx" tagName="LightBox" tagPrefix="ve"/>

You can find many samples in the web.config file of the AJAXEngine demo web site project and there is a good post on this topic in Scott Guthrie's blog too at: http://weblogs.asp.net/scottgu/archive/2006/11/26/tip-trick-how-to-register-user-controls-and-custom-controls-in-web-config.aspx

8. converting to a ASP.NET Web Control (*.cs) implementation

When writing simple controls without nested other controls there is no need to convert a UserControl into a WebControl. You need this step only when the control will be used as a wrapper to more HTML code that is declared on the web page and not within the control itself. If you download the complete source code of the AJAX Engine project you can find some advanced implementations using ASP.NET Web Controls in the APP_Code folder. Writing WebControls and designers for Web Controls is not covered here.

Sonntag, November 19, 2006

Update on the JavaScript client for SOAP based WebServices

A core element of the AJAX Engine is a JavaScript based SOAP client that is used by the browser to call methods on the server implmented by regular webservices.

Up to now only document encoding was supported by the WSDL to JavaScript transformation implemented by wsdl.xslt. I prefer using the document-literal encoding style but while working with some older JAVA implementations I decided to implement the RPC model too.

The only file that I needed to change is the wsdl.xslt file that you can download at http://www.mathertel.de/AJAXEngine/ajaxcore/wsdl.xslt.

The documentation of the SOAP client and the proxy generator can be found in the book at http://www.mathertel.de/Ajax/AJAXeBook.aspx

It's also integrated into the new downloads.

Read about the SOAP Basic Profile at http://www.ws-i.org/Profiles/BasicProfile-1.1.html

Read some arguments against the SOAP encoding at http://msdn.microsoft.com/library/en-us/dnsoap/html/argsoape.asp

Donnerstag, Oktober 05, 2006

Searching the AJAXEngine Code

Google released a new search tool named codesearch specially for coders. They support also Zip files that contain code and you can find the sources for the Ajax engine by using the link:

http://www.google.com/codesearch?hl=en&lr=&q=ajaxengine+mathertel

When you open on of the *.js files you also have a navigation through the zip file. on the top there is the path to the current opened folder and on the left side you can see al the files within that folder.

Nice feature !

Google caches the zip file so be sure to get the actual zip file from http://www.mathertel.de/AJAXEngine.

Samstag, September 16, 2006

Help on this - Scope in JavaScript

I really do not often link up to other postings on the web but in this case I have to!

Thanks to Mike West and his article "Scope in JavaScript" published at http://digital-web.com/articles/scope_in_javascript/.

I really like this article and I learned from it. It's the same story all the time: When you understand, things get easier and seems to be simpler.

If you've read my book you have noticed that I fell over the context problem when attaching JavaScript function to events. The solution I suggested was to implement a inner method that gets a usable context and there are some tricks implemented to find the right context by analyzing the target of the event.

Now, with the bind function I can reduce this overhead and we have right context right from the start.

It's not as easy as it seems

My first idea was to include the bind functionality into jcl.AttachEvent the cross browser compatible helper around attachEvent() or addEventListener() to register events but I had a lot of problems until I found that the DetachEvent is not working any more as expected.

The problem is that when using the bind() function you get a reference to a new, not the original passed function. Because you have no reference to this new function you can not use it when calling jcl.DetachEvent. If you want to detach the handler from the event you have to pass the same reference. Calling obj.detachEvent("onclick", handler.bind(obj)) will never work as expected.

... but don't give up

After some analyzing I found that most of the events are using functions that never get detached. The "on___" functions of the behavior object are automatically attached to the corresponding events but will never get detached until the page gets reloaded. These functions are now executed in the context of the bound object and it gets really access other members of the behavior.

The other situations that benefits a lot from the .bind function is when registering a timer event. Here a detach will never happen because the timer event gets canceled by using clearTimeout and you have to pass the timer, not the function reference. In many cases we need to call a method of a specific element like:

this._scrollTimer = window.setTimeout("document.getElementById('"
  + this.id + "').scrollend()", 100);

By using the bind function it looks like this:

this._scrollTimer = window.setTimeout(this.scrollend.bind(this), 100);

The other advantage you can see here is that a function reference can be passed to setTimeout which is faster than a string that gets evaluated.

New version is online

The web site was updated to this new version including a lot of new visual controls and some housekeeping bug fixes. - Get a copy from http://www.mathertel.de/Downloads/Start_AJAX.aspx or from the download area.

Sonntag, August 20, 2006

The Lightbox Visual effect

The Lightbox is another visual effect that uses the semi transparent feature available in the modern browsers.

Here is is used to simulate another layer of user interaction by hiding the existing elements of the page and bringing up new elements in front of them.

modal user interaction

This effect was found to be useful for implementing modal windows or modal dialogs.

Modal user interaction is very helpful when implementing some functionality that sometimes needs to ask the user in the middle of the implementation without breaking the usual program flow.

I'm sure that you are using this feature as well by using the alert() or prompt() methods. The JavaScript interpreter will stop executing until the opened window is closed by the user by choosing one of the available options.

There have been some discussions in the past whether modal user interactions are good or bad and especially in the apple era modal windows and dialogs where found to restrict the user's freedom.

Now with HTML pages true modal dialogs cannot be implemented any more. The Microsoft Internet Explorer offers a showModalDialog method that allows opening true modal windows. There are some tricks necessary to use this feature with dynamic build content, see http://weblogs.asp.net/datagridgirl/archive/2005/08/11/422309.aspx.

The Mozilla/Firefox offers a similar feature by using a special parameter in window.open, but you need some special privileges that are not available on the Internet to make it work.

Anyway it is all non-standard.

Lightbox implementations

You can find some implementations on the web:

http://www.blakems.com/archives/000075.html http://www.huddletogether.com/projects/lightbox/ http://particletree.com/features/lightbox-gone-wild/

or just search the word "lightbox".

I implemented a ASP.NET User Control together with a client side JavaScript Behavior that implements the lightbox effect that can be used with embedded dialog elements.

The implementation has a extensibility model implemented so you can effectively show any kind of resource that is available. Pictures for example normally have no buttons or links but you need some elements in your dialog to close the dialog, show the next element or ...

All you need to use this visual effect is to include the lightbox user control:

<ve:LightBox ID="LightBox1" runat="server" />

There can only be one lightbox element on a page. The methods coming with the behavior are all usable by calling them directly on the LightBoxBehavior.

Elements that should be displayed on top of the page can be implemented very easily using a simple div-element with a given width and height:

<div id="HelloWorld" style="display:none;width:180px;height:140px">
  <p>Hello world.</p>
  <button onclick="LightBoxBehavior.hide()">close</button>
</div>

It's a good idea to add some more style attributes to the outer <div> element to make it more look like a small dialog:

style="background-color:white;border: solid 2px #203050; padding: 2px;"

A small Image Slide Show

I've also implemented a more complex sample, a Image Slide Show. You can find the code in the implementation of this page by using the "View Source" link in the upper right corner of the page.

It is also implemented by using a JavScript Behavior and handles some keys by attaching to the keydown event.

See it in action at: http://www.mathertel.de/AJAXEngine/S04_VisualEffects/LightBoxDemo.aspx

Samstag, Juli 15, 2006

AJAX Konferenz

AJAX in action Konferenz

"--> Mit AJAX bahnt sich eine Revolution im Internet an" ist der Opener der AJAX in action Konferenz vom 27. - 28. September bei Frankfurt - zu recht wie ich meine.

Es sind viele interessante Speaker und Themen dabei. Besonders interessant ist, dass viele Plattformen vorgestellt werden und letztendlich treffen sich alle wieder im Browser mit JavaScript und XMLHttpRequest Objekten.

Was AJAX-Entwickler über Web Services wissen sollten

Mein Vortrag beschäftigt sich mit WebServices und den Protokollen die in AJAX Applikationen verwendet werden. Wer mein Blog liest (insbesondere die Beiträge im letzten Jahr rund um SOAP im Juni und Juli kennt meine persönliche Vorliebe für Standard-Protokolle. Es gibt aber noch mehr aus diesem Bereich und im letzten Jahr hat sich auch einiges getan.

Mittwoch, Juli 05, 2006

AJAX Book now available as PDF download

As requested by some people the book "Aspects of AJAX" is now available in PDF format so you can easily take it with you. I will update it from time to time when new text on theis Blog or samples on my website are written. So come back and check for new versions.

>> AJAX book download.

It's written in English so it can reach most IT people. My native language is not English so please excuse my typos or just let me know about.

AJAX Book PDF

Freitag, Juni 16, 2006

Building a AJAX enabled popup control

When fetching the extra information costs a lot of resources (cpu, memory or time) on the server or is more than just a few words it is better to not include it into the page all the time but get it from the server when the user requests for it. This scenario is perfect for using the AJAX technology.

Using the AJAX engine

To get the information from the server we need a web service with one method that gets a key string as parameter and returns the popup information. We can trust this method so far that we can rely that it is returning valid html code.

The timer object that we need to delay the popup a little bit can be completely replaced by using the delay option of the AJAX engine.

The onmouseover event code only needs to start the AJAX engine after checking for a valid html object.

ajax.Start(AJAXPopUpBehaviour.action, obj);

The action that describes the AJAX mechanism for the popUp keeps all the elements of the asynchronous execution together. It prepares the server call be fetching the url of the hyperlink, calls the GetDetails method on the server and then finishes the action by showing the popUp control.

action: {
  delay: 300,
  queueMultiple: false,
  prepare: function(obj) { return (obj.href); },
  call: "proxies.ServerInfo.GetDetails",
  finish: "AJAXPopUpBehaviour.show",
  onException: proxies.alertException
}

Using a Web Control

But it still can be easier by using a web control:

<ajax:PopUp runat="server" id="ajaxpopup1" infomethod="proxies.ServerInfo.GetDetails" />

The method that returns the information to the client is made availale to the client by including the WebService and creating a JavaScript proxy:

<script type="text/javascript"
  src="../ajaxcore/GetJavaScriptProxy.aspx?service=../S03_AJAXControls/ServerInfo.asmx">
</script>

Implementing the sample web control

On the client a JavaScript Behavior is used that is included into the page by the web control that is executed on the server. Read more and see the sample live at: http://www.mathertel.de/AJAXEngine/S03_AJAXControls/AJAXPopUpDemo.aspx.

Sonntag, Juni 04, 2006

An ASP.NET popup web contol

I just added a new control to the library that displays a popup on the page that can be used to show additional information on a specific topic or item.

A detailed description and the source can be found on my web site. Have a look at http://www.mathertel.de/AJAXEngine/S04_VisualEffects/PopUpDemo.aspx.

Dienstag, Mai 30, 2006

Visual Studio .NET add-in updated

One of my older projects where updated today.

I missed some commands so I started developing a collection of useful tools that help developing and controlling my work and files. The result was an add-in for Visual Studio that adds commands for comparing files and folders, an explore command, and some useful reports for web projects.

Give it a try at: http://www.codeproject.com/csharp/WebReports8.asp

Sonntag, Mai 28, 2006

Update to the back-button and history implementation

The last past was about implementing a back-button and local history support to the AJAX Engine.

I've added 2 attributes to the PropHistory web control that can be declared to avoid some scripting on the page:

<ajax:PropHistory runat="server" stateList="version,book,chapter" propList="vers" />

stateList specifies the page properties that together form the current state of the page. A change to the value of any of these properties will cause a new entry in the history of the browser.

propList specifies the page properties that are persisted in the hash part of the url so that hyperlinks will work.

The implementation takes care of the fact that all properties in the statList must also be part of the url but you don't have to specify them again in the propList attribute.

The download files where updated today too.

Ajax.zip contains the ASP.NET 2.0 web project that builds the side. The complete AJAX Engine and all samples are included. Use this project when you want to start building your AJAX web application.

AJAXEngine.zip This Zip-File contains the core files of the AJAX engine and the AJAX controls. You can use this if you want to update your project with the updated core files.

Freitag, Mai 12, 2006

Another view to the Back Button Problem of AJAX applications

A lot of people already wrote about this topic. Search "AJAX BACK BUTTON PROBLEM" on a search portal and you can find a lot of stuff about it!

But there are still aspects that haven't been talked about.

Let me explain that the problem is old, well known, not an AJAX specific problem and after all: technically solved.

What the back button does - and why not

Still some people think that the web is a mass of pages pointing to each other using hyperlinks. While navigating along these hyperlinks every visited page is recorded into a local list often called "history". The original idea was to support this list of pages with some functionality.

When framesets came into the browser model this simple idea got the first scratch because when you use hyperlinks that change only the content of a frame the url doesn't change. The url that you can see in the address is not the only information you need to restore a browser situation.

Up to here the back button still works in the browsers, because they also record this extra information together with the url - at least when working with the browser history functionality.

Then there are web servers that found a (not so) wonderful trick to use forms for navigating from one page to another and things get complicated. Hyperlinks can be used to submit the content of a form (including the current browser state) back to the server which then returns the next or the modified page. A problem on this approach is that the same url (main.do, main.aspx, main.jspx, main.php, ...) can be reused for the whole application.

Here the back button also has to record all the data that was posted to the server so it can be re-posted when the user wants to go one or more pages back.

This kind of request cannot in generally be distinguished by the server from clicking the same button of a form twice and often there are filters available on the server to redirect these requests to another page.

And this is why navigating back using the back button of the browser often doesn't work.

And this is why many applications start a new window at the beginning without displaying the navigation bar that includes the back button.

And this is why many users like the back button on the mouse or keyboard (ALT-LEFT).

And this is why the web doesn't work like this (too often).

The favorite problem

As with the history list a very similar problem exists with the favorites and with web urls stored in files. When you save a current page to your favorites list you might think that this helps you coming back to this page but if the server needs post information or the page is built using frames you might become disappointed because this kind of information is not stored in hyperlinks.

The IE implements a special *.url file type that is created when using the IE built in "Add to favorites..." command that contains extra information about the current urls of the frames and maybe more.

But the *.lnk file type that is created when dragging an URL from the IE address bar to the desktop as well as the url file that is created by Mozilla/Firefox doesn't hold this information.

What's the problem?

The problem with the back button existed long before AJAX applications became widely known. The core of the problem is about building a web application that works by using meaningful urls whether using frames or not and enabling the usage of the history and favorites feature of the existing browsers.

AJAX applications do have the same problem like those applications doing everything through a single url: it's meaningless and you cannot rely on any posted information because it just doesn't exist.

So what we all have to do is giving our applications meaningful urls.

Meaningful urls

Not every click should change the url and in many applications there is no clear "back" situation. If you browse your mail inbox for example a click to open a message may be a clear "navigate to" situation. When you delete the message by using a click on a button the main UI might navigate for you to the next message in the list. But where is the "back" position now - on the deleted mail?

You can also argue that moving on to the next mail is neither forward nor back but something like up and down and back will always bring you back to the list view you started.

So what I want to say is that the (forward and) back direction is often very application or problem specific. With AJAX you have the chance to model these situations the way you like and the way that is the best for your application and you are not bound to the GET and POST requests done by hyperlinks and forms.

I use the url as a textual key to the global addressable state of an Ajax application. By moving some information into the url and reading this information out of the url when a page loads or the urls changes, there is a clear interface between the Ajax page and the external world that can be used for storing browser history, favorites and links.

The back problem is technically solved

If you look for a good article on how to implement a technical solution to the problem have a look at the article "AJAX: How to Handle Bookmarks and Back Buttons" by Brad Neuberg at http://www.onjava.com/lpt/a/6293.

... by tricking IE

The Mozilla/Firefox solves this problem really straight forward and it works as expected.

When using the method window.location.replace(newHash) only the current URL is changed.

By assigning a new value to the window.location.hash property a new entry in the history list is created.

The IE is very confused about URL-hash values hat do not really point to existing anchors and does not record any history and needs a invisible iframe with a page coming from the same server. It's a little bit tricky to get all situations working and you can see the current implementation by looking into the JavaScript implementation of the PropHistory Behaviour (view source).

Implementation

The AJAXEngine already has a client side state mechanism (Page Properties or DataConnections) I introduced in September 2005 that stores key-value pairs. Instead of building a new API and leave it to the AJAX application to call a method to change the URL you only have to declare what page properties should be used in the URL. When a Page Property's value changes the URL is updated automatically and when the URL changes all connected controls will get informed about it.

When one of the properties, that define a state that should be persisted to the history changes, a new history entry is recorded.

All you need to do to make it work is to include the PropHistory control:

<ajax:PropHistory runat="server" />

and to declare what properties should be used to form the url (propList) and what subset of these properties should define the state (stateList):

<script defer="defer" type="text/javascript">
  // set default values for the Page Properties, if the value is not in the URL:
  jcl.DataConnections.Load("version", "luther1912");
  jcl.DataConnections.Load("book", "1");
  jcl.DataConnections.Load("chapter", "1");
  jcl.DataConnections.Load("vers", "1");
 
  // declare the properties that should be written to the URL:
  PropHistory.propList = {"version":"","book":"","chapter":"","vers":""};
 
  // declare the properties that are meaningful for history recording:
  PropHistory.stateList = {"version":"","book":"","chapter":""};
</script>

The sample comes from the updated Bible reader application. When you navigate through the verses of a chapter, only the URL gets changed. The navigation to a new book, version or chapter a new entry in the history stack is created.

You now also can use URLs to jump directly to some important content. Donald E. Knuth likes reading any book chapter 3 verse 16 and specially BiblePage.aspx#version=sf_kjv_strongs_rev1b&book=43&chapter=3&vers=16 and an important verse of the upcoming da vinci code movie by Dan Brown is BiblePage.aspx#version=en_gb_KJV2000_1&book=18&chapter=38&vers=11

Dienstag, April 25, 2006

Moving HTML objects using drag and drop around, CSS and JavaScript

If you want to enable a custom page layout for the user or a drag & drop functionality in your solution you need a mechanism that enables moving html objects around. Here is a cross browser compatible solution that enables moving of HTML objects.

To make it easy to attach a moving functionality to a object I use the lightweight JavaScript Behaviour mechanism that is described in the AJAX eBook found here: http://www.mathertel.de/AJAX/AJAXeBook.aspx. Especially the cross browser event handling mechanism is used here.

Attaching the mouse events

Three events must be captured to drag objects around:

onmousedown

This event starts the moving scenario and you need to attach a method to this event.

It is sometimes necessary not to move the object that got this event but to identify a specific parent object that also contains other content elements. In this demo sample the title area of a web part is used to drag the whole part around. In the method that is attached to this event the parentNode references are searched until an html object is found that is marked with the className "VEPart".

Then current mouse offset to the left upper corner of the moving object is calculated. This is because you will not start dragging by using a exactly known single point of the object.

Now that we know that a specific object should be dragged around the 2 other events must be monitored and 2 other methods are attached to them.

onmousemove

This event will be thrown multiple times and we will move the object arround by using the new mouse coordinates given each time the event gets fired.

onmouseup

This event will be thrown at the end when the user wants to place the object at the new position by releasing the mouse button.

The first event can be caught on specific objects that enable the moving. I use the CSS class "VEMover" to mark these elements and attach a move cursor. The object that is moves is marked by using the CSS class "VEPart" that contains the VEMover.

The 2 other events should be caught on the document level because they will not be thrown always on the object that initiates the moving especially when the mouse pointer is moved very fast.

Because we need a reference to the object that is moved around the onmousedown event also saves a reference to the object by using properties of the MoverBehaviour element like a global variable so we can find the object again when onmousemove and onmouseup events are caught.

A simple moveable object

<div class="VEPart" style="width:180px;height:90px">
  <div class="VEMover">::: move me</div>
  I can be moved.
</div>

The JavaScript implementation

To make the implementation easier I use my JavaScript Control Library that enables writing compatible behaviours for HTML objects. All we need here is to include the 9 kByte jcl.js file and attach the behavior to the VEMover object.

The MoverBehaviour implements the 3 event handlers:

var MoverBehaviour = {
  mo: null, // reference to the movable obj,
  x: 0, y: 0,
  
  // ----- Events -----
  onmousedown: function (evt) {
    evt = evt || window.event;
    var src = jcl.FindBehaviourElement(evt.srcElement, MoverBehaviour);
    src.MoveStart(evt);
  }, // onmousedown


  // track mouse moves. This handler will be attached to the document level !
  _onmousemove: function (evt) {
    evt = evt || window.event;
    MoverBehaviour.MoveIt(evt);
  }, // onmousemove


  // track mouse button up. This handler will be attached to the document level !
  _onmouseup: function (evt) {
    evt = evt || window.event;
    MoverBehaviour.MoveEnd(evt);
  }, // onmouseup


  // ----- Methods -----
  MoveStart: function (evt) {
    // find the moving part (position:absolute or class="VEPart")
    var mo = this;
    while ((mo != null) && (mo.className != "VEPart"))
      mo = mo.parentNode;

    if (mo == null)
      return; // don't move
    MoverBehaviour.mo = mo;
      
    // calculate mousepointer-object distance
    mo.x = mo.y = 0;
    obj = mo;
    while (obj != null) {
      mo.x += obj.offsetLeft;
      mo.y += obj.offsetTop;
      obj = obj.offsetParent;
    } // while
    mo.x = evt.clientX - mo.x;
    mo.y = evt.clientY - mo.y;

    // make the moving object globally evailable when mouse is leaving this object.
    jcl.AttachEvent(document, "onmousemove", this._onmousemove);
    jcl.AttachEvent(document, "onmouseup", this._onmouseup);
  }, // MoveStart
  

  MoveIt: function (evt) {
    var mo = MoverBehaviour.mo;
    if (mo != null) {
      var p = (evt.clientX - mo.x) + "px";
      if (p != mo.style.left) mo.style.left = p;
      p = (evt.clientY - mo.y) + "px";
      if (p != mo.style.top) mo.style.top = p;
    } // if
    // cancel selecting anything
    evt.cancelBubble = true;
    evt.returnValue = false;
  }, // MoveIt
  

  MoveEnd: function () {
    var mo = MoverBehaviour.mo;
    if (mo != null) {
      MoverBehaviour.mo = null;
      jcl.DetachEvent(document, "onmousemove", this._onmousemove);
      jcl.DetachEvent(document, "onmouseup", this._onmouseup);
    } // if
  } // MoveEnd
    
} // MoverBehaviour

jcl.LoadBehaviour("moveme", MoverBehaviour);

The sample web page is available at http://www.mathertel.de/AJAXEngine/S04_VisualEffects/MoverDemo.aspx and a brief description of the JavaScript control library is available on web site in the eBook about my AJAX engine in the chapter "Building AJAX Controls" at: http://www.mathertel.de/AJAX/AJAXeBook.aspx.

The MoverBehaviour is also available as a separate include file if you want to follow my advice of reusing behaviours by separating them into a JavaScript include file. I will have a typical WebPart sample soon and will use the mover functionality there again.

Samstag, April 22, 2006

Less waiting on AJAX

It's a psychological phenomena that waiting takes less time as long as something happens.

I'm sure you have seen all these nice rotating arrows, bouncing points or bars that are commonly used for situations where a progress bar should appear to tell the user that it's time for waiting like on the windows start up screen on http://www.pageflakes.com/ or even in windows media edition. It can also be as simple as the [Loading...] text that is used by the Google-Mail user interface.

So, when I fell over http://www.ajaxload.info last week where you can easily generate "AJAX-" animated gif files I thought it is time to implement a few lines into the AJAX Engine.

The right place to start displaying a progress indicator is just before starting the webservice call to the server. Here I call StartProgress().

But it also has to be hidden after anything happens that ends the action like when the return value is there, an exception happens or when the timeout timer strikes. To identify these places I searched the code for the ajax.current gets cleared. There I call EndProgress();

The first implementation was straight forward creating and removing a html element. After some testing I found that this costs me more time than the real call over the internet and in many situations immediate responses got slower and that's definitively not that what I wanted to achieve.

In the end I came to the following solution:

  • The StartProgress function only sets a flag (ajax.progress) to true and starts a timer (ajax.progressTimer) with a timeout of 220 msec.
  • This time was chosen by some testing and many server calls do not last so long and therefore need no progress indicator.
  • When the timer strikes it calls the ajax.ShowProgress function. Here I implement the real code that creates the HTML element or just shows an existing one again.
  • The EndProgress function clears the flag and also starts the timer but with some less waiting.
  • When the timer strikes after a call has finished the existing object is just hidden.

This architecture has some advantages. First the progress indicator is not shown when short calls are made and when multiple calls are made one after the other it is not hidden. This can save a lot of flickering.

Here are the specific new functions:

// ----- show or hide a progress indicator -----

// show a progress indicator if it takes longer...
ajax.StartProgress = function() {
  ajax.progress = true;
  if (ajax.progressTimer != null)
    window.clearTimeout(ajax.progressTimer);
  ajax.progressTimer = window.setTimeout(ajax.ShowProgress, 220);
} // ajax.StartProgress


// hide any progress indicator soon.
ajax.EndProgress = function () {
  ajax.progress = false;
  if (ajax.progressTimer != null)
    window.clearTimeout(ajax.progressTimer);
  ajax.progressTimer = window.setTimeout(ajax.ShowProgress, 20);
} // ajax.EndProgress


// this function is called by a timer to show or hide a progress indicator
ajax.ShowProgress = function() {
  ajax.progressTimer = null;
  var a = document.getElementById("AjaxProgressIndicator");
 
  if (ajax.progress && (a != null)) {
    // just display the existing object
    a.style.top = document.documentElement.scrollTop + 2 + "px";
    a.style.display = "";
   
  } else if (ajax.progress) {
    // find a relative link to the ajaxcore folder containing ajax.js
    var path = "../ajaxcore/"
    for (var n in document.scripts) {
      s = document.scripts[n].src;
      if ((s != null) && (s.length >= 7) && (s.substr(s.length -7).toLowerCase() == "ajax.js"))
        path = s.substr(0,s.length -7);
    } // for
   
    // create new standard progress object
    a = document.createElement("div");
    a.id = "AjaxProgressIndicator";
    a.style.position = "absolute";
    a.style.right = "2px";
    a.style.top = document.documentElement.scrollTop + 2 + "px";
    a.style.width = "98px";
    a.style.height = "16px"
    a.style.padding = "2px";
    a.style.verticalAlign = "bottom";
    a.style.backgroundColor="#51c77d";

    a.innerHTML = "<img style='VERTICAL-ALIGN:bottom' src='" + path + "ajax-loader.gif'> please wait...";
    document.body.appendChild(a);

  } else if (a) {
    a.style.display = "none";
  } // if
} // ajax.ShowProgress

You can find the full source here and I will also include it into the next ajax.zip.

If you want to see how it looks like you can use the old prime factor sample. Try some long the numbers like: 98798798789878987. You might see it only if someone else is stressing the server too - It seems to be a powerful machine :-) and prime factors get calculated fast even with my stupid algorithm :-).

Donnerstag, April 20, 2006

Simple sliding sample to move HTML elements around

Moving HTML objects to new positions is not hard to implement. You can use absolute positioning and just set the style attributes left and top to the new values but it doesn't look cool if the objects use this kind of hyper speed: the eyes cannot follow and there may be a confusing effect of a sudden rearrangement.

Moving objects more slowly can be simulated by moving them using several steps and only a small distance at once. All we need is a timer to start the next step after the current position is rendered, a little bit of algebra and a heuristic to find the right distance for one step.

Because no local variables can be used when executing timer scripts we declare 4 global variables that hold all the information we need when the next step is to be started:

var slidingTimer = null; // the current running timer object
var slidingTarget = null; // the moving object
var slidingLeft = null; // the target left position
var slidingTop = null; // the target top position

Starting a sliding movement can be done by calling the startSlidePos function with 3 parameters: the object that should be moved, the new left and the new top coordinate. You can also refer the object by using the unique id.

onclick="startSlidePos('i', 10, 270)"

Every timer event now calculates the remaining vector but takes no more than 20 pixel length or a third of it whatever is shorter. Only if the target is very close the object will be positioned exactly:

// calc the remaining vector
dx = slidingLeft - left;
dy = slidingTop - top;

// calc the movement length along the vector
len = Math.sqrt(dx * dx + dy * dy);
delta = Math.min(20, len/3);

if (len <= 2) {
  // snap exactly
  left = slidingLeft;
  top = slidingTop;

} else {
  left += Math.round(dx * delta / len);
  top += Math.round(dy * delta / len);
} // if

Using this calculation the movement gets slower at the end when the target is almost reached.

You can see the full source code by using the view source functionality of your browser or in the right upper corner of the page.

You can find the sample live at: http://www.mathertel.de/AJAXEngine/S04_VisualEffects/SlidingDemo.aspx

Montag, April 17, 2006

HTML elements with rounded corners

HTML elements up to now have always a rectangle shape. In the upcoming CSS3 standard (still a proposal) there might be also other border shapes available including rounded corners by specifying a border radius. But we do not have to wait to get this visual effect shown up.

The trick that is shown here to get the usual rectangle corners into a round shape is to use a collection of thin HTML elements to build a non rectangle border.

The simplest solution to this is to use <div> at the top and bottom and arrange them like this:

Why not using a client side solution

The Rico framework for example is offering a client-side method to round the elements:

<div id='roundDemo' style='width:300px'>Insert content here.</div>
<script>Rico.Corner.round('roundDemo', {corners:'tl br',bgColor:'#adba8c'});</script>

By using a JavaScript solution on the client to generate these elements every div element can be transformed to a rounded corner look. The disadvantage of this approach is that there is always a delay and maybe a light flickering because the page will get rendered twice because the borders will be expanded by adding the additional elements.

Why not using graphic elements

I've also seen solutions that use 4 specific corner graphics. The drawback about this approach is that the colors of these images must correspond exactly to the colors of the other html elements. If you want to change your style then you must change the images too. Again here will be a light flickering because images are often loaded after displaying the page for the first time so it doesn't look very perfect.

A server-side solution

It is also possible to generate all the additional html elements on the server. This adds some html tags and some more data to the http response when the page gets loaded but also eliminates a lot of JavaScript or images.

For ASP.NET I've written a web control that derives from asp:Panel that does the same and avoids the flickering:

<ajax:RoundedArea runat='server' id='any' width='300'>Insert content here.</ajax:RoundedArea>

You can see a live sample of it at http://www.mathertel.de/AJAXEngine/S04_VisualEffects/RoundedDemo.aspx.

Samstag, April 08, 2006

HTML + CSS Shadow Effect with real transparency

If you want to give your objects a kind of 3D feeling then you might want to use shadows for those objects that are placed upon the web page.

Using special graphics

A often solution for a shadow effect is to use table layout around the main content and arrange a set of graphics around the right and bottom border. You can get really wonderful shadow dropping effects using this approach but because semi transparent images are not very well supported on IE you will have to pay attention to the background color you use on the page and have to mix it into your shadow images.

Using a Microsoft IE specific CSS filter attribute

When using the IE only you can also us one of the wonderful filter effects that are available in this browser. Just add a CSS filter attribute like that:

filter: progid:DXImageTransform.Microsoft.dropShadow(Color=AAAAAA,offX=8,offY=8,positive= true);

If you use IE that you can see these shadows on the entry page for the visual effects library. These shadows are also drawn by using solid colors.

Using CSS opacity

Here is a better solution that really resembles a kind of shadow because the text and graphics in the shadow are really displayed in dimmed light. The clue to this effect is a built-in opacity CSS graphics effect that is available IE, Mozilla, Firefox - but in different way.

In Internet Explorer:  style="filter: alpha(opacity= 50)"

The IE notation of the opacity effect is using a proprietary CSS attribute named filter that can be used to add various effects to a HTML element. Here we use the alpha filter.

In Mozilla/Firefox: style= "-moz-opacity:0.5"

The Mozilla / Firefox provides a proprietary css attribute named -moz-opacity that allows specifying a opacity value.

In Opera: style= "opacity:0.5"

The Opera browser also has a proprietary css attribute named opacity that allows specifying an opacity value.

These 3 CSS attributes can be combined together and every browser ignores all the attributes that are unknown:

style="filter: alpha(opacity= 50); -moz-opacity:0.5; opacity: 0.5" 

The HTML shadow object

This effect must be applied to rectangle region with a fixed width and height that is over the main content by using an absolute position by using the same size as the html part that is dropping this shadow.

Here is a simple sample that uses this trick. You can see it live at ShadowDemo.aspx.

The good about this solution is, that no graphics are used and that the shadow does not hide the text below but only seems to dim the available light.

  • The outer div element is used to do the absolute positioning of the whole group.
  • The first inner <div> element is the object that has the opacity effect applied. It is positioned some pixel to the right and down by using an absolute positioning (relative to the containing <div>) too.
  • The Content is placed inside the second inner <div> element that must have a relative position without any offset to be displayed above the shadow object.

Here is the plain HTML code:

<div class="VEPart" style="position: relative; width: 120px; top:-90px; left: 40px;">
  <div class="VEShadow" style="position: absolute; left: 10px; top: 10px;
    width: 120px; height: 84px; background-color: black;
    filter: alpha(opacity=30); -moz-opacity: 0.3; opacity: 0.3;"> </div>
  <div class="VEContent" style="position: relative; height: 80px;
    background-color: #FFFFDD;"> I am flying above the text and dropping a shadow.</div>
</div> 

You can see how it looks like on the demo website at http://www.mathertel.de/AJAXEngine/S04_VisualEffects/ShadowDemo.aspx

Montag, April 03, 2006

Why AJAX needs visual effects

Implementing a web based application by using AJAX techniques is about improving the backside, will elable the right user experience and will make your application work the way it should.

If you want that your application really looks like AJAX you also have to give your application a modern design together with all kinds of visual effects. That will really impress!

Don't you think that this is nonsense ? - I did for some time last year but I had to change my mind - at least a little bit.

Visual effects are definitvely an important aspect for AJAX applications today. Maybe the "market" will learn the technical difference in some near future. Maybe a "get-it-all-together" solution is the right approach for the "market".

So here is a list of visual effects and other "cool" looking stuff. Some of these effects can also be used in any other html based application, some of them will use AJAX. I'll explain the HTML+CSS+JavaScript that makes the effect but I will also bring the higher level approach using ASP.NET web controls that makes using them really easy.

AJAX applications look great! :-)

So here comes a library of visual effects. From time to time I will add another one and you will find them also on the demo side at http://www.mathertel.de/AJAXEngine/ see Examples -> Visual Effects .

The documentation you will find here on my blog and (with a little delay) in the AJAX eBook at http://www.mathertel.de/ajax/eBook.aspx. You will not find only a working solution but also a brief description on how it works so you can also use it in any of your projects too.

Samstag, März 04, 2006

SOAP was made for AJAX

I recently ran over the blog of Dave Winer and his post from Sun, Sep 12, 1999 titled "An end to the Über-Operating System". see: http://davenet.scripting.com/1999/09/12/anEndToTheUberoperatingSystem

... The purpose of both specs [SOAP and XML-RPC] is to enable scripted web applications to cross operating system boundaries.

Of course the term AJAX was not known then but I thing that "scripted web applications that cross operating system boundaries" is a good definition of AJAX. By using SOAP there even is more XML on the wire than with AJAX applications using a JSON or plain text transport protocol.

Ask yourself: what is or should be the standard protocol for AJAX applications when retrieving data from the server? - By using SOAP many aspects of a transport layer have been discussed (data types, attachments ...) and there are even more upcoming standard extensions for it (security, routing ...).

The only thing that I really miss is a built-in native SOAP client in browsers.

The (deprecated) SOAP spec from 1999: http://www.oasis-open.org/cover/draft-box-http-soap-00.txt. I think that this doc is one of the most influencing documents I've read. It disappeared from the Microsoft site and http://www.ietf.org. Does anybody know who feels responsible for achieving historical documents from the internet?

Thanks to Don Box, Dave Winer and all the other founders of SOAP.

Sonntag, Februar 19, 2006

Use web services with multiple parameters in the AJAX Engine

In the past moths I've got mails that all request for more functionality in the javascript webservice proxies and the AJAX engine so I've added more support for datatypes and arrays in december last year and got some more compatibility with other SOAP implementations then ASP.NET.

I've also got some requests that describe to reuse existing web services that have multiple parameters on a AJAX page and I think this is a valid request.

While it is possible to use web methods with multiple parameters when using the web service proxies layer directly, the AJAX engine level is only supporting one parameter - but there is a small trick that help you out of this situation.

The AJAX engine knows about all the asynchronous steps that have to be done to complete the whole functionality through the declaration of an action object. The details about that can be found in the documentation at http://www.mathertel.de/ajax/Aspects%20of%20AJAX_index.htm. See the chapter about the "AJAX Actions".

Now have a look how this mechanism can be used with multiple webservice parameters. You can find a sample that simply adds 2 integers at http://www.mathertel.de/AJAXEngine/S02_AJAXCoreSamples/CalcAJAX.aspx

The prepare function is normally used for retrieveing the client-side parameter from the html objects. Because we need more than one parameter we just do nothing here except returning the context object.

The call function, that is called next is not just pointing to the proxy function of the method of the web service but needs some more code. It retrieves all the parameters itself and then calls the proxy method webservice. The trick is, that the mechanism that handles asynchronous result messages is not hooked up correctly and must be patched by using 2 lines of code for the regular and the exception case:

proxies.CalcService.AddInteger.func = this.call.func;
proxies.CalcService.AddInteger.onException = this.call.onException;

Now the call will be processed asynchronously and the result value will be passed to the finish function as usual.

Here the complete code that declares the AJAX action:

// declare an AJAX action
var action1 = {
  delay: 200, // wait for multiple keystrokes from fast typing people
 
  // the prepare function just returns the context object (if any)
  // and makes it available to the call function.
  prepare: function(obj) { return (obj); },

  // the call is not pointing to the webservice proxy directly but calls it using several parameters.
  call: function (obj) {
    var n1 = document.getElementById("n1").value;
    var n2 = document.getElementById("n2").value;
    proxies.CalcService.AddInteger.func = this.call.func; // patch
    proxies.CalcService.AddInteger.onException = this.call.onException; // patch
    proxies.CalcService.AddInteger(n1, n2); // and call
  },
 
  // the result will now be processed as usual.
  finish: function (p) { document.getElementById("outputField").value = p; },
 
  onException: proxies.alertException
} // action1

Samstag, Februar 04, 2006

Comparisation of AJAX frameworks

Daniel Zeiss, who is the man behind the ComfortASP.NET framework see http://www.comfortasp.de/ has published a very interesting comparison on his web site (http://www.daniel-zeiss.de/AJAXComparison/Results.htm) and his blog (http://www.geekswithblogs.com/danielz).

(Have you noticed that there are many German developers involved in AJAX engines and frameworks?)

I have also implemented the simple sample he uses for the comparison at http://www.mathertel.de/AJAXEngine/S02_AJAXCoreSamples/AJAXComparison.htm.

My annotations on these results

The Aspects of AJAX Engine is consuming less bytes on the network that most of the other machines in this comparison.

The size of the transferred bytes is indeed a very interesting aspect. I have not spent any time in reducing this value and I also have no chance to reduce the bytes of a standard SOAP call without leaving this standard and adding the need to implement server specific code.

The initial transfer of the page is smaller than the original ASP.NET version mainly because I do not need any ASP.NET functionality for deploying a working page.

The biggest part of the Engine is the ajax.js file with 21876 bytes because it contains a lot of comments and additional information. I could reduce this page in a view minutes by stripping off all the comments and blank lines down to 12000 bytes and it can be reduced even more. Thats the size that should be used in the comparison because the other frameworks also only send optimized include files.

The other AJAX implementations are very strong bound to the ASP.NET programming model and therefore have to solve many content-update topics - That's what Daniel Zei calls "indirect AJAX programming". The Aspects of AJAX Engine only transfers data on the network and must right now implement content changes on the client using JavaScript. This is also true for many other "direct AJAX programming" environments. By using AJAX enabled controls, even this work is not necessary because the controls can handle themselves and only the developer of the control itself has to think about it.

Freitag, Februar 03, 2006

Aspects of AJAX: An Engine for Java

This AJAX Engine was originating published in 2005 for the ASP.NET 2.0 Platform and is now partly also available in JAVA. This Engine can be ported very easily because it relies on web standards that are available on many platforms and in many languages:

JavaScript / ajax.js

A huge part of the coding is done using JavaScript on the client. This code needs shared by both projects and is always exchangeable.

WebServices

The asynchronous calls from the page in the browser to the server are implemented using the SOAP standard. On the server we only need Standard WebServices. Both platforms, ASP.NET and Java support the bottom up implementation of WebServices and we just need to write simple methods that get called from the client.

XSLT / WebService Proxies

To enable a communication from the client side, the server uses the WSDL definitions that can be generated from WebServices on both platforms and transforms them to proxy objects using JavaScript.

The retrieval of the WSDL and for the transformation is ported and needs only about 30 lines of code that you can find in ~/ajaxcore/GetJavaScriptProxy.aspx or ~/ajaxcore/GetJavaScriptProxy.jsp.

The definition of the translation itself is coded using an xslt definition in the file ~/ajaxcore/wsdl.xslt that is also identical on both platforms.

The AJAX Engine needs nothing else than these 3 building blocks.

Download

The download is available on my web side: http://www.mathertel.de/AJAXEngine/ in the download section containing a eclipse project. I use right now: Eclispe 3.1.2 with the Webtools plug-in 1.0, Java 1.4.2.x, Tomcat 5.5 incl. the compatibility jar and Axis 1.2.1

Documentation

If you search for more documentation use the following links that are part of the ASP.NET version written in C#. Java programmers should understand the code very easily and there are also many JavaScript hints and tricks documented in there.

http://www.codeproject.com/soap/JavaScriptProxy_01.asp A early available documentation about how the JavaScript proxies are generated and how they work.

http://ajaxaspects.blogspot.com/ The blog where all you can find all the documentation that was written while the project was growing.

http://www.mathertel.de/AJAXEngine/ The ASP.NET based demo WebSide containing all the samples I talked about in my blog.

http://www.mathertel.de/ajax/Aspects of AJAX_index.htm An eBook about the AJAX Engine. Here you can find most of the content of the blog and some more hints.

Please contact me via my blog and let me know how you find this work - and what you miss.

Dienstag, Januar 31, 2006

AJAX for ASP.NET

I've got several questions about what .NET version the AJAX Engine is supporting.

The answer is: .NET 2.0

BUT, most of the AJAX programming is done using JavaScript that runs on the client side and the AJAX part on the server is implemented by standard webservices and some people started porting the code to JAVA...

If you know about ASP.NET 1.1 it should be possible for you to port the sources back to ASP.NET 1.1 and I've written a some text about the concepts behind my ideas that may help.

Samstag, Januar 07, 2006

An AJAX based Tree View for the Bible

I just published another Page displaying a English Bible using an AJAX Tree View Control. It just took me half an hour, including some other housekeepings.

Have a Look at http://www.mathertel.de/AJAXEngine/S03_AJAXControls/BibleTreeView.aspx.

Mittwoch, Januar 04, 2006

TreeView sample did not run with FireFox - Bug fixed!

The TreeView sample I posted yesterday did not run with FireFox. - I just did not test it and did not find it in time.

I fixed the bug today and it works now. Changes are in ~/controls/TreeView.js.

Dienstag, Januar 03, 2006

Tree View AJAX Control

The sample page is available at: http://www.mathertel.de/AjaxEngine/S03_AJAXControls/TreeView.aspx.

Hierarchically structured data can be found in various places on this world. File systems, network structures, dependencies, organisation charts, bill of materials etc. are hierarchical by nature or by design or can be viewed to be so.

(I personally think that the reason behind the fact that so many structures are hierarchically organized is that more complex structures are too chaotic to be understood easily.)

Displaying hierarchical data as trees is relatively easy to be implemented and you can find many implementations with ASP.NET Controls on the web. But when it comes to mass data situations (like the content of a file system) it is almost impossible to load the complete tree at. A simple paging approach, that is known from huge table-data doesn't fit for structured data.

Displaying this kind of data of a good place for using the AJAX technology and the architecture of my AJAX controls is also used here. The best solution is to load and open only the root level of the tree when loading the page and to load all sub-levels when the user wants to dig down by clicking a folder. Already loaded sub-levels can stay at the client until the page gets reloaded.

The AJAX engine can be used to solve the server call in the background very easily by using a WebService that can be queried for sub-level data. With JavaScript and the XMLhttp object this data can be requested from the server an transformed into html code to display all the nested items.

1. Defining a contract

The AJAX control, after beeing loaded will use a WebService for retrieving the list of sub-nodes (folders and files) from a given node (the user clicks). A WebService that can be used for this purpose has a very simple interface with only a single method. The parameter is used with a key that uniquely defines a already known folder node and the return value is a structure with the folders and files under that node.

The unique key of a node can be described by a path string and the return value is typed as a XML document:

[WebMethod]
public XmlDocument GetSubNodes(string path);

Every folder and every file must have a name that must be unique among the subnodes of a folder ans we can concatinate these names as we usually do for filesystems to get a overall unique identifying string.

The returned XML has the form:

<folder>
  <folder name="[name of the folder]" title="[some more text]" />
  <file name="[name of a file]" title="[some more text]" />
</folder>

There can be as multiple files and folders in any order.

2. Implementing a WebService

The WebService implementation we need is very simple. I've published a version that loads a XML file and uses this data source.

3. Javascript and HTML: building a tree layout

There are many <table> - based sample implementations for tree structures on the web. I use a very simple approach here that works fine but supports the indenting of subnodes, but no lines in front of the icons that uses <div>-elements. Here is the basic structure of a folder with the container of the subnodes:

<div class="du" name="foldername"><span class="ft">foldertitle</span></div>
<div class="subframe"></div>

The click event is captured at the root level and has to do the following things:

  • identify the clicked folder object (<div> with class=[do|dc|de|du])
  • hiding (do) or showing (dc) the container with the subnodes
  • or starting an AJAX action (du) that loads the subnodes

4. the AJAX action

The context parameter of the only ajax action we need is the node of the folder with the still unkown subnodes.

The prepare function builds the path string for this folder.

The asynchronous call will return the xml document that is passed to the finish method.

In the finish method we transform the returned xml document into the html wee need by using a simple xslt transformation that can be found inline in the file of the page.

All we have to code for that is an AJAX Action:

  // Retrieve the sub-nodes of a given folder.
  ExploreAction: {
    delay: 10,
    queueMultiple: true,

    prepare:
      function(src) { 
        var path = "";
        var root = jcl.FindBehaviourElement(src, TreeViewBehaviour);
        while ((src != null) && (src != root)) {
          if (src.className == "subframe") {
            src = src.previousSibling;
          } else if (src.className == "do") {
            path = "/" + src.name + path;
            src = src.parentNode;
          }
        }
        while (path.substr(0,2) == "//")
          path = path.substr(1);
        return (path);
      },

    call: "proxies.TreeView.GetSubNodes",

    finish:
     function(data, src) {
       jcl.FindBehaviourElement(src, TreeViewBehaviour).ExtendTree(src, data);
     },
    
    onException: proxies.alertException
  }, // FetchAction

That's still a lot of code, so we build a Control to get that coding off from our daily work by implementing a control.

5. the AJAX control

All the coding up to here should be covered by the AJAX Control so the developer only adds this control with the following attributes:

<ajax:TreeView runat="server" title="Cities of USA" service="WebServiceAlias" />

The title attribute is the label shown on the root folder.

The service attribute is the alias name of the web service that serves the data of the tree

The complete implementation can be found in the 2 files that build the AJAX Control and the JavaScript behaviour: TreeView.ascx and TreeView.js that can be found in the controls folder.