February 15, 2008

Beahvioral Action Model- Part Two

Filed under: Programming — Ben Jones @ 9:42 am

In Part One, we built a very simple page with a single button that made use of some Behavioral Action Model techniques. From part one, we had the following function that provided the muscle for our button:

function link()
{
  var btn     = document.getElementById("mybutton");
  btn.onclick = function() { self.location = 'mypage.html'; }
}

This function was made available to the document by means of the body tag’s “onload” method. This works just fine for a few functions but breaks down rather quickly when the complexity begins to rise. Fear not though, the mechanism still applies. With a little coaxing and a touch JavaScript’s flexibility, we can continue undaunted.

For starters, it would more convenient if we didn’t need to actually create a “btn” reference from within the function. Something more like the following perhaps:

function link()
{
  btn.onclick = function() { self.location = 'mypage.html'; }
}

We could then pass the “btn” reference in as an argument of the function:

function link(btn)
{
  btn.onclick = function() { self.location = 'mypage.html'; }
}

To make all of this a bit more “generic”, let’s replace the “btn” name for something less specific, like “element”.
Rewriting the above function with our substitution yields the following.

function link(element)
{
  element.onclick = function() { self.location = 'mypage.html'; }
}

At this point, we have returned to something extremely similar to our original “goto” function from part one:

function goto(url) { self.location = url; }

Although these two are similar, there are some major differences. While the latter “goto“, function is just that, a function. The former “link” function has evolved into JavaScript’s version of a class. This classifying, if you’ll pardon the expression, has created a class Link that contains an “onclick” method. We can add additional methods as well.

function Link(element)
{
  element.onclick     = function() { self.location = 'mypage.html'; };
  element.onmouseover = function() { };
  element.onmouseout  = function() { };
}

The Link class now has some extra muscle that be applied to the element under differing contexts. It can now respond to “click“, “mouseover“, and “mouseout” events. This is fine, but how do we make use of this improved link function?

In part one, we used the onload method to install the script that directly bound itself to the element. This time we will inject a little abstraction into the mixture giving us a lot more flexibility. Instead of loading “Link” class directly, we’ll install a loader function that will in turn load this class. We still have an issue with the “Link” class itself. It is not directly bound to an element as it was originally, but rather accepts a reference to one instead. So, how do we tie our class to the desired element or elements?

In JavaScript, classes are Objects and can be thus be members of other Objects. We can in fact store our “Link” class with all its methods within another Object, like an array. This would give us the ability to
store many other classes; Luckily, JavaScript offers us not only an array but also an associative array (otherwise known as maps, or hashes). Why is this so lucky you ask?

Associative arrays are special in that the array stores data as key-value pairs where the key is literally the means to access the value. This is ideal for our purposes since the key can be a text string instead of a numerical index. Let’s use the “Link” class to illustrate this point.

function Link(element)
{
  element.onclick     = function() { self.location = 'mypage.html'; };
  element.onmouseover = function() { };
  element.onmouseout  = function() { };
}

If we extract the class name to use as the key, namely “Link”. Then the contents of the class become the matching value. Since the key is text, it has been set into single quotes.

'Link' : function (element)
{
  element.onclick     = function() { self.location = 'mypage.html'; };
  element.onmouseover = function() { };
  element.onmouseout  = function() { };
}

The colon denotes an associative pair. The text string on the left is the key; while, the remaining class definition becomes the value on the right hand side. Now that our class has been converted into a key-value pair, it needs to be added to a container Object. We’ll name our Object “bam_classes” and make the assignment as follows:

var bam_classes =
{
'Link' : function (element)
{
  element.onclick     = function() { self.location = 'mypage.html'; };
  element.onmouseover = function() { };
  element.onmouseout  = function() { };
}
};

Having our class definition stored as a value tied to its function name as the key further adds a subtle layer of abstraction. Remember that the name is a text string and thus could be any string and not necessarily a traditional function or class name, like “myFunc” or “accountsPayable”. Pulling a quote from part One, …”any valid element tag, class,
attribute, or combination thereof can be used” brings us to an important juncture.

In part one, our button element was styled with the class “goLink” and had and id attribute of “mybutton“. There is no reason why we can’t use this information as the key for our class definition that is stored in the “bam_classes” Object. Fortunately, CSS provides a convenient nomenclature for just this case:

var bam_classes =
{
'button.goLink#mybutton' : function (element)
{
  element.onclick     = function() { self.location = 'mypage.html'; };
  element.onmouseover = function() { };
  element.onmouseout  = function() { };
}
};

Having the ability to use CSS selectors as the key for stored classes is a major step forward in both expressive power and the extraction of control and logic code from presentation code. We can now tie functionality to elements as broadly as all buttons, or as discretely as button of “some_class” that has an id of “some_id

Finally, we have reached the point where we jump back to the loader function that is being called in the body’s “onload” method. The purpose of the loader class is to attach all our functionality encapsulated in the bam_classes Object to their corresponding elements. The loader extracts the keys from the bam_classes Object then parses through the DOM elements within the document looking for matches. Each matched element becomes a reference that is used by the attached function.

{end part two}

February 3, 2008

Behavioral Action Model - Part One

Filed under: Programming — Ben Jones @ 12:23 pm

This is a brief tutorial on using the behavioral action model. Fundamentally, this is just a clean separation between HTML and Javascript scripting that relies on Javascript’s ability to modify the DOM. In essence, we are attaching Javascript functions to events on DOM elements using CSS as an identification system.

Let’s start with a simple button element that will link us to another page:

<button onclick="javascript:location='mypage.html'">My Page</button>

Nothing fancy, a very basic button that gets the job done with no styling. Now create a basic style for the button that gives us a font of choice and a size of 20 pixels.

.goLink { font-family:Verdana; font-size:20px; }

There, a basic style. Now let’s apply that style to our button:

<button class="goLink" onclick="javascript:location='mypage.html'">My Page</button>

Again, this is nothing fancy, just a basic button and an applied style. From this point, things begin to diverge.
What we intend to happen is that when the button is “clicked” we jump to the link provided.
Since our goal is to pull out the javascript, let’s start by cleaning up the button a bit into
something a little more concise.

<button onclick="goto('mypage.html');'">My Page</button>

This is a little cleaner, but now requires a supporting Javascript function like below:

function goto(url)
{
  self.location = url;
}

We now have a Javascript function that actually does the work when its called from within the
button by the “onclick“. But we still have Javascript in our button! Yes, but not for long.
Lets rewrite the button again and this time pull out the “onclick” event entirely.

<button class="goLink">My Page</button>

There, a really minimal button indeed. Unfortunately, our button no longer jumps to the page when clicked.
To fix this, we need to re-attach that “goto” function to the button without embedding it back into
the button. Using Javascript we can grab the element in question with a “getElementById” call
but we don’t have an “id” attribute on that button. So let’s add one:

<button class="goLink" id="mybutton">My Page</button>

Now we can do something like this:

var btn = document.getElementById("mybutton");

Doing this gives us a Javascript object that is referenced to the button element. We now have a means
by which to re-attach our “goto” function. This looks a little like the following:

btn.onclick = goto;

That statement literally adds an “onclick” method onto our object “btn” and
assigns it to a function called “goto“.
So, we’re getting closer by the moment. What we need to do now is package all this up a little neater and make
it accessible to the browser. In fact, we could even define the “goto” function within this little
package making everything even more concise.

function link()
{
  var btn     = document.getElementById("mybutton");
  btn.onclick = function() { self.location = 'mypage.html'; }
}

To activate this link function, we need to use the “onload” method of the body element.

<body onload="link();">

By using the “onload” we’re telling the browser to load up the functionality found in our “link
function and this would in turn make our button do its intended business. So what does this really look like in practice.
Let’s look at a little page that uses this technique.

<html>
<head>
<title>My Test</title>
<style>
   .goLink { font-family:Verdana; font-size:20px; }
</style>
<script>
function link()
{
  var btn     = document.getElementById("mybutton");
  btn.onclick = function() { self.location = 'mypage.html'; }
}
</script>

<body onload="link();">

<button class="goLink" id="mybutton">My Page</button>

</body>
</html>

We should now pull out the CSS definitions and all the Javascript from the HTML file and place
them into their own external files much like the following rewrite of the page:

<html>
<head>
<title>My Test</title>

<script type="text/javascript" src="link.js"></script>
<link rel="stylesheet" type="text/css" href="goLink.css"/>
</head>

<body onload="link();">

<button class="goLink" id="mybutton">My Page</button>

</body>
</html>

By doing this, we have very tight and clean HTML and likewise concise supporting files for
both the CSS and the Javascript.

Now comes the next step, ramping up the possibilities. We are not limited to using only id
attributes to attach functionality, any valid element tag, class, attribute, or combination
thereof can be used for this purpose. Using CSS notation, we could have attached our “goto
function more specifically to the button using something like ‘button.goLink#mybutton’.
Our link function would have to be rewritten to look for buttons, then for those buttons
of class “goLink” which then have an id attribute of “mybutton“.
While this might seem a bit much, it is extremely useful and very practical.

This is where a nice little Javascript library comes into play, called “Behaviour”, that
allows us to chain together our definitions into a single
Javascript object and then apply those definitions to the entire DOM with a single call.
Nice. Very nice indeed.

{end part one}

Powered by WordPress