haXe 2: Using Templates

Exclusive offer: get 50% off this eBook here
haXe 2 Beginner's Guide

haXe 2 Beginner's Guide — Save 50%

Develop exciting applications with this multi-platform programming language

$26.99    $13.50
by Benjamin Dasnois | July 2011 | Open Source Web Development

haXe is the universal programming language which is completely cross-platform and provides a standard library that remains the same—regardless of platform. Templates are a very useful feature of haXe. They help the developer with his job of presenting data to the user by making it easy to repeat some parts of a view (or page) and by allowing some branching depending on data.

In this article by Benjamin Dasnois, author of haXe 2 Beginner's Guide: RAW, we will cover templating by talking about:

  • The included haxe.Template class
  • The syntax used by the templating system
  • How data is passed to the templating system
  • How a template can execute some actions

So if you are ready, let's go!

 

haXe 2 Beginner's Guide

haXe 2 Beginner's Guide

Develop exciting applications with this multi-platform programming language

        Read more about this book      

(For more resources on this subject, see here.)

Introduction to the haxe.Template class

As developers our job is to create programs that allow the manipulation of data. That's the basis of our job, but beyond this part of the job, we must also be able to present that data to the user. Programs that don't have a user interface exist, but since you are reading this article about haXe, there is a greater chance that you are mostly interested in web applications, and almost all web applications have a User Interface of some kind. However, these can also be used to create XML documents for example.

The haXe library comes with the haxe.Template class. This class allows for basic, yet quite powerful, templating: as we will see, it is not only possible to pass some data to it, but also possible to call some code from a template.

Templates are particularly useful when you have to present data—in fact, you can, for example, define a template to display data about a user and then iterate over a list of users displaying this template for each one.

We will see how this is possible during this article and we will see what else you can do with templates. We will also see that it is possible to change what is displayed depending on the data and also that it is easy to do some quite common things such as having a different style for one row out of two in a table.

The haxe.Template is really easy to use—you just have to create an instance of it passing it a String that contains your template's code as a parameter. Then it is as easy as calling the execute method and giving it some data to display.

Let's see a simple example:

class TestTemplate
{
public static function main(): Void
{
var myTemplate = new haxe.Template("Hi. ::user::");
neko.Lib.println(myTemplate.execute({user : "Benjamin"}));
}
}

This simple code will output "Hi. Benjamin". This is because we have passed an anonymous object as a context with a "user" property that has "Benjamin" as value.

Obviously, you can pass objects with several properties. Moreover, as we will see it is even possible to pass complex structures and use them.

In addition, we certainly won't be hard coding our templates into our haXe code. Most of the time, you will want to load them from a resource compiled into your executable by calling haxe.Resource.getString or by directly loading them from the filesystem or from a database.

Printing a value

As we've seen in the preceding sample, we have to surround an expression with :: in order to print its value.

Expressions can be of several forms:

Form

Explanation

::variableName::

The value of the variable.

::(123)::

The integer 123. Note that only integers are allowed.

::e1 operator e2::

Applies the operator to e1 and e2 and returns the resulting value.

The syntax doesn't manage operator precedence, so you should wrap expressions inside parenthesis.

::e.field::

Accesses the field and returns the value.

Be warned that this doesn't work with properties' getters and setters as these properties are a compile-time only feature.

Branching

The syntax offers the if, else, and elseif:

class TestTemplate
{
public static function main(): Void
{
var templateCode = "::if (sex==0):: Male ::elseif (sex==1)::
Female ::else:: Unknown ::end::";
var myTemplate = new haxe.Template(templateCode);
neko.Lib.print(myTemplate.execute({user : "Benjamin", sex:0}));
}
}

Here the output will be Male. But if the sex property of the context was set to 1 it would print Female, if it is something else, it will print "Unknown".

Note that our keywords are surrounded by :: (so the interpreter won't think that it is just some raw-text to be printed).

Also note that the "end" keyword has been introduced since we do not use braces.

Using lists, arrays, and other iterables

The template engine allows one to iterate over an iterable and repeat a part of the template for each object in the iterable.

This is done using the ::foreach:: keyword. When iterating, the context will be modified and will become the object that is actually selected in the iterable.

It is also possible to access this object (indeed, the context's value) by using the __current__ variable.

Let's see an example:

class Main
{
public static function main()
{
//Let's create two departments:
var itDep = new Department("Information Technologies Dept.");
var financeDep = new Department("Finance Dept.");

//Create some users and add them to their department
var it1 = new Person();
it1.lastName = "Par";
it1.firstName = "John";
it1.age = 22;

var it2 = new Person();
it2.lastName = "Bear";
it2.firstName = "Caroline";
it2.age = 40;

itDep.workers.add(it1);
itDep.workers.add(it2);

var fin1 = new Person();
fin1.lastName = "Ha";
fin1.firstName = "Trevis";
fin1.age = 43;

var fin2 = new Person();
fin2.lastName = "Camille";
fin2.firstName = "Unprobable";
fin2.age = 70;

financeDep.workers.add(fin1);
financeDep.workers.add(fin2);

//Put our departements inside a List:
var depts = new List<Department>();
depts.add(itDep);
depts.add(financeDep);

//Load our template from Resource:
var templateCode = haxe.Resource.getString("DeptsList");
//Execute it
var template = new haxe.Template(templateCode);
neko.Lib.print(template.execute({depts: depts}));
}
}

class Person
{
public var lastName : String;
public var firstName : String;
public var age : Int;

public function new()
{

}
}

class Department
{
public var name : String;
public var workers : List<Person>;

public function new(name : String)
{
workers = new List<Person>();
this.name = name;
}
}

In this part of the code we are simply creating two departments, some persons, and adding those persons into those departments.

Now, we want to display the list of departments and all of the employees that work in them. So, let's write a simple template (you can save this file as DeptsList.template):

<html>
<head>
<title>Workers</title> </head>
<body>
::foreach depts::
<h1>::name::</h1>
<table>
::foreach workers::
<tr>
<td>::firstName::</td>
<td>::lastName::</td>
<td>::if (age < 35)::Junior::elseif (58):
:Senior::else::Retired::end::</td>
</tr>
::end::
</table>
::end::
</body>
</html>

When compiling your code you should add the following directive:

-resource DeptsList.template@DeptsList

The following is the output you will get:

<html>
<head>
<title>Workers</title> </head>
<body>

<h1>Information Technologies Dept.</h1>
<table>

<tr>
<td>John</td>
<td>Par</td>
<td>Junior</td>
</tr>

<tr>
<td>Caroline</td>
<td>Bear</td>
<td>F</td>
</tr>

</table>

<h1>Finance Dept.</h1>
<table>
<tr>
<td>Trevis</td>
<td>Ha</td>
<td>Senior</td>
</tr>

<tr>
<td>Unprobable</td>
<td>Camille</td>
<td>Retired</td>
</tr>

</table>

</body>
</html>

As you can see, this is indeed pretty simple once you have your data structure in place.

Time for action – Executing code from a template

Even though templates can't contain haXe code, they can make calls to so-called "template macros". Macros are defined by the developer and, just like data they are passed to the template.execute function. In fact, they are passed exactly in the same way, but as the second parameter.

Calling them is quite easy, instead of surrounding them with :: we will simply prefix them with $$, we can also pass them as parameters inside parenthesis. So, let's take our preceding sample and add a macro to display the number of workers in a department.

First, let's add the function to our Main class:

public static function displayNumberOfWorkers(resolve :
String->Dynamic, department : Department)
{
return department.workers.length + " workers";
}

Note that the first argument that the macro will receive is a function that takes a String and returns a Dynamic. This function will allow you to retrieve the value of an expression in the context from which the macro has been called.

Then, other parameters are simply the parameters that the template passes to the macro. So, let's add a call to our macro:

<html>
<head>
</head>
<body>
::foreach depts::
<h1>::name:: ($$displayNumberOfWorkers(::__current__::))</h1>
<table>
::foreach workers::
<tr>
<td>::firstName::</td>
<td>::lastName::</td>
<td>::if (sex==0)::M::elseif (sex==1)::F::else::?::end::</td>
</tr>
::end::
</table>
::end::
</body>
</html>

As you can see, we will pass the current department to the macro when calling it to display the number of workers.

So, here is what you get:

<html>
<head>
</head>
<body>

<h1>Information Technologies Dept. (2 workers)</h1>
<table>

<tr>
<td>John</td>
<td>Par</td>
<td>M</td>
</tr>

<tr>
<td>Caroline</td>
<td>Bear</td>
<td>F</td>
</tr>

</table>

<h1>Finance Dept. (2 workers)</h1>
<table>

<tr>
<td>Trevis</td>
<td>Ha</td>
<td>M</td>
</tr>

<tr>
<td>Unprobable</td>
<td>Camille</td>
<td>?</td>
</tr>

</table>

</body>
</html>

What just happened?

We have written the displayNumberOfWorkers macro and added a call to it in the template. As a result, we've been able to display the number of workers in a department.

Integrating subtemplates

Sub-templates do not exist as such in the templating system.

The fact is that you can include sub-templates into a main template, which is not a rare process. Some frameworks, not only in haXe, have even made this standard behavior.

So, there are two ways of doing this:

  • Execute the sub-template, store its return value, and pass it as a property to the main template when executing it.
  • Create a macro to execute the sub-template and return its value. This way you just have to call the macro whenever you want to include your sub-template in your main template.

Creating a blog's front page

In this section, we are going to create a front page for a blog by using the haxe.Template class.

We will also use the SPOD system to retrieve posts from the database.

haXe 2 Beginner's Guide Develop exciting applications with this multi-platform programming language
Published: July 2011
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

Time for action – Creating our SPOD class

First, let's create a very simple SPOD class representing our blog posts.

Add this code to Post.hx:

class Post extends neko.db.Object
{
public var id : Int;
public var title : String;
public var body : String;

public static var manager = new neko.db.Manager<Post>(Post);
}

You also have to create the corresponding table in your SQL database. You can create it and name it "myBlog".

In order to do so, you can use the following SQL statement:

CREATE TABLE 'Post' (
'id' INT NOT NULL AUTO_INCREMENT,
'title' TEXT NOT NULL,
'body' LONGTEXT NOT NULL,
PRIMARY KEY ( 'id' )
) ENGINE = MYISAM;

Once you have done this, our SQL database is set up correctly and we have objects to work with. You may want to populate it with some dumb posts:

INSERT INTO 'expressCafe'.'Post' (
'id' ,
'title' ,
'body'
)
VALUES (
NULL , 'First Post', 'Hi, this is the first post of this blog!'
), (
NULL , 'Second post', 'This is the second post in a not so long
series of articles.'
);

You may also execute the following if you want two more posts:

INSERT INTO 'expressCafe'.'Post' (
'id' ,
'title' ,
'body'
)
VALUES (
NULL , 'Third post', 'This is the third post in our series of
articles.'
), (
NULL, 'Fourth and last post', 'Hi, this is the fourth and last post
of our series!'
);

Time for action – Connecting to the database

In our main function, let's initiate the connection to our database and the SPOD system:

import Post;

class Main
{
public static function main()
{
//Parameters to connect to the MySQL database
var cnx = neko.db.Mysql.connect({
host : "localhost",
port : 3306,
database : "myBlog",
user : "root",
pass : "",
});

//Initialize the SPOD system
neko.db.Manager.cnx = cnx;
neko.db.Manager.initialize();

//We've done our processing, let's clean things and disconnect
neko.db.Manager.cleanup();
cnx.close();
}
}

When doing this, we can successfully connect to the database although it won't do anything at the moment.

Now, let's just retrieve our posts from the database by simply adding this:

var posts = Post.manager.all();

We now have the following:

import Post;

class Main
{
public static function main()
{
//Parameters to connect to the MySQL database
var cnx = neko.db.Mysql.connect({
host : "localhost",
port : 3306,
database : "myBlog",
user : "root",
pass : "",
});

//Initialize the SPOD system
neko.db.Manager.cnx = cnx;
neko.db.Manager.initialize();

var posts = Post.manager.all();

//We've done our processing, let's clean things and disconnect
neko.db.Manager.cleanup();
cnx.close();
}
}

So, we now have all our Posts at our disposal when we want to use them in our template.

Time for action – Creating our template

Now, let's create a template that will simply take an object with the property posts to hold our list of posts.

Add this code to your template.html file:

<html>
<head>
<title>List of Posts</title>
</head>
<body>
<!-- Simply display a greeting -->
<h1>Hi and welcome on my blog!</h1>
<!-- Iterate over all Posts -->
::foreach posts::
<!-- Display's the blog post's title -->
<h2>::title::</h2>
<!-- Display's the blog post's body -->
<div>::body::</div>
::end::
</body>
</html>

You will also want to include this file as a resource named template.

To do so, just add the following to your compilation command:

-resource template.html@template

That's all it takes.

Time for action – Reading the template from resources

To read our template from resource and store it, we will simply add these lines of code:

var templateCode : String;
templateCode = haxe.Resource.getString("template");

So, we now have the following:

import Post;

class Main
{
public static function main()
{
//Parameters to connect to the MySQL database
var cnx = neko.db.Mysql.connect({
host : "localhost",
port : 3306,
database : "myBlog",
user : "root",
pass : "",
});

//Initialize the SPOD system
neko.db.Manager.cnx = cnx;
neko.db.Manager.initialize();

var posts = Post.manager.all();

var templateCode : String;
templateCode = haxe.Resource.getString("template");

//We've done our processing, let's clean things and disconnect
neko.db.Manager.cleanup();
cnx.close();
}
}

Time for action – Executing the template

Now that we have loaded our template's code, we will want to execute it.

In order to do that, we have to take the following steps:

  1. Create an instance of haxe.Template passing it the value of templateCode.
  2. Pass an object with a property named posts and having our List of Posts, as a value so that they can be processed by our template.
  3. Execute our template.
  4. Print its result.

The first step is done easily with the following line of code:

var template = new haxe.Template(templateCode);

The second step can be accomplished this way:

var context = {posts : posts};

Executing the template is just as simple and we don't even need to pass it any macro. We just need to do the following:

var result = template.execute(context);

Finally, you certainly must have guessed it, to print the result we will just do the usual:

neko.Lib.print(result);

So, our complete Main class is:

import Post;

class Main
{
public static function main()
{
//Parameters to connect to the MySQL database
var cnx = neko.db.Mysql.connect({
host : "localhost",
port : 8889,
database : "myBlog",
user : "root",
pass : "",
socket : null
});

//Initialize the SPOD system
neko.db.Manager.cnx = cnx;
neko.db.Manager.initialize();

var posts = Post.manager.all();

var templateCode : String;
templateCode = haxe.Resource.getString("template");

var template = new haxe.Template(templateCode);

var context = {posts : posts};

var result = template.execute(context);

neko.Lib.print(result);

//We've done our processing, let's clean things and disconnect
neko.db.Manager.cleanup();
cnx.close();
}
}

Time for action – Testing the result

You can simply execute this program and you should get the following output:

<html>
<head>
<title>List of Posts</title>
</head>
<body>
<!-- Simply display a greeting -->
<h1>Hi and welcome to my blog!</h1>
<!-- Iterate over all Posts -->

<!-- Displays the blog post's title -->
<h2>First Post</h2>
<!-- Displays the blog post's body -->
<div>Hi, this is the first post of this blog!</div>

<!-- Displays the blog post's title -->
<h2>Second post</h2>
<!-- Displays the blog post's body -->
<div>This is the second post in a not so long series of
articles.</div>

<!-- Displays the blog post's title -->
<h2>Third post</h2>
<!-- Displays the blog post's body -->
<div>This is the third post in our series of articles.</div>

<!-- Displays the blog post's title -->
<h2>Fourth and last post</h2>
<!-- Displays the blog post's body -->
<div>Hi, this is the fourth and last post of our series!
</div>
</body>
</html>

This is exactly what we were waiting for.

Note that this example is pretty simple but you may want to change the style of posts depending on the author.

In addition, our comments here take up quite a lot of space for the "useful code". Even though our file is pretty small here, it certainly isn't a good idea to almost multiply the size of your file per 2, especially if you're going to make it transit over the Internet. So, you may want to have a look at such things and clean them up.

One last thing: even though in this article we've always used our templating system in order to generate HTML, it is also possible to use it to make reference to the haXe templating system to generate any other kind of text-based files. So, you may want to generate XML files using this system. It can be really useful for quite a lot of things.

Have a go hero – Doing more with the thing

Let's imagine we want to take our blog example a bit further: use it as a starting point, and add a link for each blog post in order to delete it.

Summary

In this article, we've been talking about the haXe's standard templating system. As we've seen, it's not difficult to use and allows one to do quite a lot of interesting things such as easily generating an HTML page or generating other kind of text-files such as XML files (and even any kind of interface that uses XML as a describing language).

Specifically, we covered how to instantiate templates and give a context to them. We've also learnt how to do testing and branching in templates and calling code from them.

This article, although quite simple, exposes important information that you will certainly use many times while developing applications.

Also, remember that you cannot access an object's property using a template. This is a very important limitation of haxe.Template.


Further resources on this subject:


haXe 2 Beginner's Guide Develop exciting applications with this multi-platform programming language
Published: July 2011
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Benjamin Dasnois

Benjamin Dasnois has always been fascinated by open source software and as such, has been giving courses about Linux in an IT school in France. In the meantime, Benjamin has been following and working with haXe since its beginning and uses it in his professional life. He now works on an open source project, started the integration of haXe into it, and made it work with the technologies that were already in use.

Books From Packt

Agile Web Application Development with Yii1.1 and PHP5
Agile Web Application Development with Yii1.1 and PHP5

Python 3 Web Development Beginner's Guide
Python 3 Web Development Beginner's Guide

Grok 1.0 Web Development
Grok 1.0 Web Development

Flash Development for Android Cookbook
Flash Development for Android Cookbook

Mastering phpMyAdmin 3.1 for Effective MySQL Management
Mastering phpMyAdmin 3.1 for Effective MySQL Management

jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery

Learning Ext JS 3.2
Learning Ext JS 3.2

MODx Web Development - Second Edition
MODx Web Development - Second Edition

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software