Finally! Version 2.0 is here. Overview about the Highlights    News

Long time, long time. It seems that nothing happend, but it did. After a lot of work I am proud to present you version 2.0. It's been quite a while in the pipeline but now it is here with loads of updates and additions. All that thanks to your feedback!

So whats new? One of the most popular updates is the addition of so called page parts. They allow us to load XHTML fragments directly into our page using the existing and famous ajaxed.callback function.

The other important addition is a powerful debugging tool: A Logger! Version 2.0 contains a ready-to-use logger with ASCI colorization support. It allows you to debug your own code and provides you insight information about what the library does. Perfect for debugging our AJAX callbacks as well.

I am not sure if that is important to mention as some might say Email is too common. But! ajaxed provides you now an email wrapper. You don't care about email components anymore.

Beside all that additions there are new classes like: a Localization class for gathering information about the client, DataContainer which acts as an abstract container for all kinds of data structures, a Validator which helps you validating data, a StringBuilder which lets us work with huge amount of strings.

Last but not least there are two new amazing controls. One is a Dropdown - it allows you generating dropdowns within seconds. The other one is the giant within ajaxed:

And many, many more small updates & bug fixes. Please refer to the changes.txt for the details. Read some details about the highlights below.

Real world samples

First of all you should know that this website is totally developed with ajaxed. Why is that so important? Because the entire source code has been released for the public.
Just go, browse our code and see how we did it.

Okay, so here is the overview of the highlights...

Database

ajaxed has been fully tested with MySQL, MS Access, MS SQLServer and sqlite and Oracle. Take it easy if you want to use one of them.

Probably the biggest change to the database has been the addition of getRS() and getUnlockedRS() methods. Those replace the prior methods getRecordset() and getUnlockedRecordset(). Although all are still supported its recommended to use the new ones. They give you the ability of parametrized SQL queries. In other words - everthing is done to prevent SQL injection. The names are also shorter :) check the changes:


<%
'before
set RS = db.getRecordset("SELECT * FROM user WHERE id = " & str.sqlSafe(id))
'now
set RS = db.getRS("SELECT * FROM user WHERE id = {0}", id)
%>


When using update() or insert() all the text fields are trimmed to the maximum allowed length. This mean no errors anymore if the input is too long as allowed by the database field.

Added a insertOrUpdate() method which allows you to insert a record if it does not exist yet and update it if its already there. With update() you can also perform batch updates now.

Page parts

So far ajaxed.callback could only return different data types but it could not return whole page fragments. Lets say you wanted to implement a tab control where each tab loads different XHTML from your server. This is now possible with page parts. Just prefix a server side procedure with pagePart_ and use the name as the action parameter within ajaxed.callback:

<!--#include virtual="/ajaxed/ajaxed.asp"-->
<%
set page = new AjaxedPage
page.draw()

sub main() %>

  <button type="button" onclick="ajaxed.callback('one', 'content')">content 1</button>
  <button type="button" onclick="ajaxed.callback('two', 'content')">content 2</button>

  <div id="content"></div>

<% end sub %>

<% sub pagepart_one() %>

  the first content

<% end sub %>

<% sub pagepart_two() %>

  some other content from server side

<% end sub %>
Run this code — pageparts.asp


When the second parameter is a string (like in the example) then its assumed to be an element which will be updated with the page parts content. You can still provide a JavaScript function. In case of a page part it will receive the HTML returned by the page part.

Logger

I have seen that debugging AJAX calls can be a bit hard. Thats why here comes the Logger into the game. You can use the logger to trace page requests, database access, etc. Last but not least you are able to add your own log messages.
Read this article to get more details about the logger.

Email

Do you know the pain when working with emails? All the different components and what happens if you switch the hosting provider? Then you might probably need to rewrite your email sending code. Not anymore! ajaxed offers you an powerful email wrapper class. It even comes with powerful features as: Piping all emails to one email, debugging emails, etc.
Read the detailed article about Emails within ajaxed.

Datatable

Our new giant within ajaxed is called Datatable. It lets you grab data from the database and display it in a tabular form. Including sorting, paging, searching, etc. All fully ajaxed! Perfect for backends. We love SQL and we use it. That's why the Datatable is focused on SQL queries as datasource.

There will be an own tutorials section on how to use the Datatable, as its a control with a lot of functionality. You can do incredible stuff with it. For the beginning I want to show you the first example using the popular Northwind database :)

<!--#include virtual="/page.asp"-->
<!--#include virtual="/ajaxed/class_datatable/datatable.asp"-->
<!--#include virtual="/ajaxed/class_dropdown/dropdown.asp"-->
<%
set table = new Datatable
set page = new AjaxedPage
page.draw()

sub init()
  db.open(DATA_CONNSTRING)
  table.sql = "SELECT * FROM person"
  table.recsPerPage = 10
end sub

sub callback(action)
  table.draw()
end sub

sub main() %>

  <% table.draw() %> 

<% end sub %>
Run this code — datatable.asp

Please refer to the API for more details and usage examples of the Datatable. This is the first version and it has some small bugs but the main features are working perfectly. E.g. Language support will be added soon. Also styles have to be provided by yourself yet as it still looks a bit naked. Go on, the CSS classes are already within the markup - just styling is missing.

DataContainer

Did you ever needed to page a recordset in your application? I bet you had :) Pagination, this is just one cool functiona of our new DataContainer. This class is loaded by default. Here is a short demonstration:

<!--#include virtual="/ajaxed/ajaxed.asp"-->
<%
set page = new AjaxedPage
page.draw()

sub main()
  'create a new datacontainer for an array
  set data = (new DataContainer)(array("first", "second", "Second", "third"))

  'write some details about it
  str.writef "First Element: {0} <br/>", data.first
  str.writef "Last Element: {0} <br/>", data.last
  str.writef "Count: {0} items <br/>", data.count

  'get only unique elements
  for each el in data.unique(false)
    str.write(el & "<br/>")
  next
end sub
%>
Run this code — datacontainer.asp


Thats cool. An example of pagination will follow soon. Check the documentation if you need it now. DataContainer can be used with a Dictionary or Recordset as well. Even simple arrays are supported. You just don't care anymore whats the underlying data strucuture.

Validator

Do you use Models within your application? Probably not as it's not so common for classic ASP - but it does not matter. The Validator provides you the base for any kind of validation. Use it to validate your models or use it directly in your views.

Basically the Validator acts as a container for error messages (which are result of invalidity). You can ask it if its valid, add new messages to it, iterate through the errors, get an error summary or even return them directly within an AJAX call. Here is a quick example using AJAX:

<!--#include virtual="/ajaxed/ajaxed.asp"-->
<!--#include virtual="/ajaxed/class_validator/validator.asp"-->
<%
set page = new AjaxedPage
page.draw()

sub callback(a)
  if a = "save" then
    'create new validator
    set v = new Validator
    'if the name is empty add an error
    if page.RFT("name") = "" then v.add "name", "Name required"
    'if age is not a number or less than 1 then error
    if page.RFP("age", 0) < 1 then v.add "age", "Age invalid"
    'thanks to ajaxed we can return the whole
    'object. it implements the reflect() method
    page.return v
  end if
end sub

sub main() %>

  <script>
    function save() {
      ajaxed.callback('save', function(r) {
        //easy access to the validator properties.
        if (!r.valid) return $('errors').update(r.summary);
        alert('Successully saved. No errors :)');
      })
    }
  </script>

  <form id="frm" onsubmit="save();return false;">
    <ul id="errors"></ul>
    Your Name:
    <input type="text" name="name"/>
    <br/>
    Your Age:
    <input type="text" name="age"/>
    <br/>
    <input type="submit" value="save"/>
  </form>

<% end sub %>
Run this code — validator.asp


Localization

Modern web applications need to know everything about the client and localize it according to its information. We cannot know everything but we try hard :) The new Localization class offers information about the client and its settings. An instance is available by default through the local variable. Here is one example which locates you (it should show the country of your ISP):

<!--#include virtual="/ajaxed/ajaxed.asp"-->
<%
set page = new AjaxedPage
page.draw()

sub main()
  'get the countrycode with timeout of 5 seconds
  countryCode = local.locateClient(5, empty)
  if isEmpty(countryCode) then str.writeEnd("Service unavailable")
  if countryCode = "XX" then str.writeEnd("Location unknown")
  str.writef "You are located in '{0}', arent you?", countryCode
end sub
%>
Run this code — local.asp

Really useful stuff if you are working with goecoding services such as google maps API. You can provide content localized to the visitor.

Dropdown

We believe that a dropdown is really important in web applications and that the implementation is usually are real mission. Thats why ajaxed introduces a fully flexible Dropdown class. It's optimized for performance and allows you to get rid of the spaghetti code involved with creating dropdowns. Check a simple example:

<!--#include virtual="/ajaxed/ajaxed.asp"-->
<!--#include virtual="/ajaxed/class_dropdown/dropdown.asp"-->
<%
set page = new AjaxedPage
page.draw()

sub drawDD()
  with new Dropdown
    'you can also use SQL, Dictionary, ...
    .datasource = array("Jack Johnson", "John Meyer")
    .name = "myDD"
    .multiple = page.QS("t") <> ""
    if .multiple then .size = 2
    if page.QS("t") = "multipleS" then
      .multipleSelectionType = DD_SELECTIONTYPE_SINGLE
      .size = 50
    elseif page.QS("t") = "multipleM" then
      .multipleSelectionType = DD_SELECTIONTYPE_MULTIPLE
      .size = 50
    end if
   .draw()
  end with
end sub

sub main() %>

  <a href="?t=">classic</a>
  <br/>
  <a href="?t=multiple">multiple classic</a>
  <br/>
  <a href="?t=multipleS">multiple single selection</a>
  <br/>
  <a href="?t=multipleM">multiple multi selection</a>
  <br/>

  <% drawDD() %>

<% end sub %>
Run this code — dropdown.asp


StringBuilder

Ever needed to concatenate a large amount of strings? This can get slow really quickly. This is a common problem not only in classic ASP. For this reason I have implemented a StringBuilder class which takes advantage of the available .net String Builder (System.IO.StringWriter). Yes, we are gettnig help from .net. Thats great! So whenever you are working with a lot of data consider using the StringBuilder (e.g. Datatable makes heavy use of it already as it usually deals with large sets of data):

<!--#include virtual="/ajaxed/ajaxed.asp"-->
<%
set page = new AjaxedPage
page.draw()

sub main()
  'create new instance
  set o = new StringBuilder
  for i = 0 to 10000
    'append some value
    o("Hello world")
  next
  'output the concatenated string
  str.write(o.toString())
end sub
%>
Run this code — stringbuilder.asp


Header &: Footer

The AjaxedPage provides you a property called headerFooter. This makes it possible to define a page header and footer explictly. Programatically. This could be a "master page" for all your page now:


<!--#include virtual="/ajaxed/ajaxed.asp"-->
<%
with new AjaxedPage
  .headerFooter = array("pageHeader", "pageFooter")
  .draw()
end with
%>

<% sub pageHeader() %>
  <html><body>
<% end sub %>

<% sub pageFooter() %>
  </html></body>
<% end sub %>


Test Fixtures

The coolest addition within our TestFixture is the ability to check the response of any page of your application. You can quickly write tests to check if all pages are working correctly (at least are accessible and do not throw an error). Write a test like this:


<!--#include virtual="/ajaxed/class_testFixture/testFixture.asp"-->
<%
set tf = new TestFixture
tf.run

sub test_1
  tf.assertResponse "/somePage.asp", empty, "<h3>.*?</h3>", "Page seem not to work"
end sub
%>


Write tests for every of your pages and find useful assertions for the response (using regular expression pattern). This helps you find problems faster in the future.

Regular Expressions

Small functions but massive power. Two new string functions join our compilation. Both deal with Regular expressions and make code so much more readable. rReplace() replaces all occurrences according to a regex pattern wheras matching() only checks if a string matches it. The idea for the latter comes from Ruby on Rails =~ operator ;)


<%
'checks if numbers exist in a given string
isNumber = str.matching("2", "^\d$", true)
'removes all numbers from a string
noNumbers = str.rReplace("abcd2efg4", "\d", "", true)

'Note: the last parameter has to do with
'case sensivity. check the API for it.
%>


New String & Request Utilities

There is not much to say here as code can say more than thousand word.
"Code is poetry" - wordpress


<%
'get values from forms auto-trimmed
name = page.RFT("name")

'get from querystring, form and parse immediately
'before
id = str.parse(page.RF("id"), 0)
id = str.parse(page.QS("id"), 0)
'now
id = page.RFP("id", 0)
id = page.QSP("id", 0)

'combine str.write and str.format
'before
str.write str.format("say {0}", "hello")
'now
str.writef "say {0}", "hello"

'str.format can be used without array too (if only one arg)
'before
str.format "say {0}", array(10)
'now
str.format "say {0}", 10

'StringOperations default function HTML encodes string
'dont forget to encode all your user input
'to prevent attacks such as XSS
str.write(str("<please encode me>"))
%>


Documentor

Lots of updates made to the documentor. To see its capabilities just check the recent API Docs. Remember: you can use the documentor also for your own classic ASP source code.

Last note

As you can see this update is really huge. All those functions are working in production systems already so you can easily upgrade to the new version. It will help you to be more productive in the future.

Upgrading from 1.0

Upgrading from version 1.0 should be no problem at all if you did not change any source files. Please read the changelog carefully if you have huge applications running with ajaxed and be sure to backup your running system.

Thanks to everyone ajaxed is getting nicer and getting more attention. Our goal is to make the tool for all the legacy ASP applications out there. Help us, provide your feedback.

Michal

Posted in News 5592 days ago

Version 2.1.1 Released3926 days ago