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:
- A fully AJAX driven Datatable (also know as Datagrid).
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