Articles: 843 | Categories: 148   
   
   
Home Articles Contact Us
 
 
 
 
Prototype Data Types (0 Comments)
Admin: Posted Date: April 4, 2010

In this I will teach you about the different data types that can be used in Prototype (on top of the existing JavaScript data types).The first data types we will look are the basic string and number types.

Prototype Data Types

Introduction

In this, the third article in the "Eight Weeks of Prototype" series, I will teach you about the different data types that can be used in Prototype (on top of the existing JavaScript data types).

The first data types we will look are the basic string and number types. Prototype extends these JavaScript types to give you more control over their behaviour.

Next we will look at the Enumerable class, which is used to manage a series of values. Once we have covered the way Enumerable works and is used, we will look at the Array and Hash data types, both of which are examples of an Enumerable type.

In this article I will assume you have read and understand the first two articles in this series.

The String Object

The first data type we will look at is the String object. Prototype extends this object to give you a wider range of methods that can be called on strings.

Each of these methods can be applied directly to a string literal, or to variables that hold strings. For instance, one of the functions made available is strip(), used to remove whitespace before and after a string (just as the PHP function trim() works). Listing 1 shows two different ways you can use this method. The first way in this example is to call strip() directly on a variable, while the second way is to apply strip() directly to a literal string.

Listing 1 The different ways to apply string functions (listing-1.html)
<html>
<head>
<title>Two different ways of applying string methods</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<script type="text/javascript">
var string = ' test ';
var result = string.strip();
// result holds the string 'test'
var result = ' test '.strip();
// result holds the string 'test'
</script>
</body>
</html>

Rather than covering every method available, I'll cover a few basic ones to begin with, and then give you an idea of some other useful string functions that are available when using Prototype.

String Testing

The first functions we will look at are for string testing. That is, each method returns a Boolean value (true or false). Several examples of using each of the methods covered here are shown in Listing 2.

Firstly, the empty() method. This method returns true if the target string has zero-length. An alternative to using this method is to use the expression myVar.length == 0.

Next, the blank() method. This method returns true if the target string has no characters or contains only whitespace. Be aware that line feeds are treated as whitespace. The alternative to using this method is to combine the strip() and empty() methods we have already looked at. That is, myVar.blank() will return the same value as myVar.strip().empty().

Now we will look at the include() method. Although the name is slightly misleading, this method checks whether or not a string contains an instance of another string. You can use regular expressions as an alternative to this method, although for a simple test this method will work fine. For instance, if (myVar.include('bar') { ... } will work the same as if (/bar/.test(myVar)) { ... }.

Similar to include() are the startsWith() and endsWith() methods. Rather than searching for a substring anywhere in the string, the substring must occur at the beginning or end of the string respectively. Once again you can use regular expressions to achieve this functionality. In the case of startsWith(), you would use the ^ symbol at the start of the regular expression (to signify the match must occur at the start of the string), while you would use the $ symbol to match at the end of the string. For example, if (myVar.endsWith('foo')) { ... } will function the same as if (/foo$/.test(myVar)) { ... }).

Listing 2 Using the blank(), empty(), include() and endsWith() methods (listing-2.html)
<html>
<head>
<title>Using the blank(), empty(), include() and endsWith() methods</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<script type="text/javascript">
var string = '';
// string.empty() returns true
var string = '  ';
// string.empty() returns false
// string.strip().empty() returns true
var string = '  ';
// string.blank() returns true
var string = 'foo';
// string.blank() returns false
var string = '';
// string.blank() returns true
var string = '\n';
// string.blank() returns true
var string = 'The quick brown fox';
if (string.include('fox'))
alert('The string contains fox!');
if (!string.endsWith('.'))
string += '.';
alert(string);
</script>
</body>
</html>

Other Useful String Methods

Some other string methods that you may find useful are listed below.

  • isJSON() - Check whether a string contains syntactically correct JSON data
  • camelize() - Turn a dash-separated string into camel-caps. This is useful for translating CSS properties into their DOM equivalent. For instance, 'background-color'.camelize() returns backgroundColor.
  • capitalize() - This method formats a string so the first letter of each word is a capital while the rest of the letters are lower case. This is the equivalent of using ucwords(strtolower($str)) in PHP.
  • escapeHTML() - This method converts certain characters into their correct HTML entities. For instance, '&lgt;'.escapeHTML() would return the string &lt;.
  • toQueryParams() - Parse the query string from a URL into an object of key/value pairs. This is similar to the PHP parse_str() function, and will result in data similar to that of the PHP's $_GET superglobal.
  • truncate() - Shorten a string to a specified length and append a suffix to it. This is useful when you want to show only a partial string but want to indicate there is more to it. For example, 'The Quick Brown Fox'.truncate(12, '...') would return The Quick....
Note: This is similar to the truncate modifier in the Smarty Template Engine, except that Smarty also has the option to append the suffix without breaking up a word, whereas this method does not.

There are many more string functions available, so you should read over the Prototype documentation to find out more about them.

The Number Data Type

Prototype extends the native JavaScript number type with a range of new methods, each of which can be applied similarly to string methods. 

For the most part, these methods are just wrappers to the normal Math object methods. For example, the abs() method corresponds to the Math.abs() method. Similarly, the ceil(), floor() and round() methods also correspond to the respective Math method.

Aside from these methods, the only other methods of any great use are the toColorPart() and toPaddedString() methods.

The toColorPart() method is used to convert a number (assumed to be in the range of 0 to 255) to a 2 character hexadecimal number. This allows you to easily create a CSS colour string.

Listing 3 shows how toColorPart can be used. Later in this article we'll look at another way of using this method by making use of the array methods Prototype provides.

Listing 3 Creating hex colour codes with toColorPart() (listing-3.html)
<html>
<head>
<title>Creating hex colour codes with toColorPart()</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<div id="foo">
This div will change colour!
</div>
<script type="text/javascript">
var r = 255;
var g = 100;
var b = 0;
var hex = '#' + r.toColorPart()
+ g.toColorPart()
+ b.toColorPart();
// hex will have the value #ff6400
$('foo').setStyle({ backgroundColor : hex });
</script>
</body>
</html>

The toPaddedString() method is useful for created a zero-padded string based on the target number. For example, calling (25).toPaddString(5) will result in a string 5 characters in length. That is, 00025.

Enumerable Data Types

An enumerable data type is one that contains a series of values over which you can loop. There are already two such types in JavaScript (that is, arrays and objects), however Prototype provides a united interface for accessing for accessing each of these types in the same manner. Additionally, Prototype makes it possible for you to create your own enumerated types, all of which extend from the Enumerable object.

For example, regardless of the type of data the your enumerated type holds, you can call the size() method to determine the number of elements in the enumerable object.

Note: There is a slight ambiguity between JavaScript objects and the Prototype Hash object. Hash is an extension of the normal JavaScript object, but as we will see later in this article, values are read and written differently since Prototype 1.6.0. When you create a new JavaScript object, it is not automatically a hash (unless arrays, which are automatically extended).

The each() Method

Let's firstly look at the each() method, which is one of the most important functions made available to Enumerablecode> objects. In order to use each(), you pass an iterator function as the first argument. When the each() call is executed, the iterator function is called once for each element in the enumerable object. The current element is passed as the first argument to the iterator, while the second argument containers the iteration number (beginning from 0).

In order to demonstrate, let's revisit the $$() function. This function returns an array of elements that match the CSS selector(s) passed in as arguments. Using each(), we can easily perform operations on every matched element.

Listing 4 shows two examples of selecting all of the items in an unordered list and changing them slightly. We've already seen how $$() and the update() method works in previous articles, but we're now also using each(). In the first part of the example we define the iterator callback inline when performing the each, while in the second part of the example it is defined as a separate function.

Listing 4 Basic usage of each() on an array (listing-4.html)
<html>
<head>
<title>Basic usage of each() on an array</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<div id="foo">
<ul>
<li>Element 1</li>
<li>Element 2</li>
<li>Element 3</li>
<li>Element 4</li>
</ul>
</div>
<script type="text/javascript">
$$('#foo li').each(function(item) {
item.update(item.innerHTML + ' -- modified!');
});
function doSomething(item)
{
item.setStyle({ backgroundColor : '#f60' });
}
$$('#foo li').each(doSomething);
</script>
</body>
</html>

When using each() to loop over data, it is important to know how to control the loop. In PHP (and other languages), you can use the break or continue expressions to do so. Using break in PHP means the loop execution is halted there and then, while continue halts the current iteration but continues on with the loop.

Achieving continue functionality within each() is simple. Because each iteration is a function call, you can simply use return to emulate continue. The current function call is terminated and the function will be called again for the next iteration.

In order to break the loop, Prototype provides a special variable called $break. If you throw this variable as an exception, Prototype will know to end the loop. Listing 5 shows an example of continuing and breaking a loop. This example will read the text inside each list item and write it to the #output div.

As mentioned above, the iteration number is passed as the second argument to the iterator callback. In this example we skip outputting a message for the third iteration, and finish the loop after the fourth element.

Note: The iteration number is zero-indexed, so this value will be 2 for the third iteration and 3 for the fourth iteration.
Listing 5 Breaking and continuing each() loops (listing-5.html)
<html>
<head>
<title>Breaking and continuing each() loops</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<div id="foo">
<ul>
<li>Element 1</li>
<li>Element 2</li>
<li>Element 3</li>
<li>Element 4</li>
<li>Element 5</li>
<li>Element 6</li>
</ul>
</div>
<div id="output"></div>
<script type="text/javascript">
function doSomething(item, i)
{
var output = $('output');
if (i == 2)
return; // "continue"
output.update(output.innerHTML + '<br />' + item.innerHTML);
if (i == 3)
throw new $break;
}
$$('#foo li').each(doSomething);
</script>
</body>
</html>

Other Enumerable Methods

In addition to each(), there are a number of other methods that can be used with enumerable objects. There are many different functions available (too many to cover here).

One example of one of these useful extra methods is invoke(). This method allows you to call a single function on each element in the enumerable.

For example, if you use $$() to select a number of elements, you can hide all elements by using invoke() to apply the hide() method. That is, you can use $$('#foo li').invoke('hide').

You can also pass arguments for the method to invoke. For example, to remove the active class name from all elements, you could use $$('#foo li').invoke('removeClassName', 'active').

Object Context

Most of the methods in the Enumerable accept an extra argument, used to define the context of the iterator method. Essentially what this does it define what the keyword this refers to when used inside of the iterator.

While this is an extremely important concept in development with Prototype, it is generally only relevant when developing your own classes in Prototype.

Arrays

Prototype automatically extends the array type to give all of the functionality of enumerables. That is, you can you use methods such as each() on any array that you create.

Revisiting Listing 3 (which created a CSS colour string from 3 different variables), we can define the colours as an array then use the invoke() method (covered above) to create the string.

Listing 6 shows an example of doing so. When we call invoke with toColorPart() as the function to execute, an array is returned with each element corresponding to the result for each element in the input array. We can then join this value to create a single string from the returned array.

Listing 6 Using arrays and invoke to create hex colour codes (listing-6.html)
<html>
<head>
<title>Using arrays and invoke to create hex colour codes</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<div id="foo">
This div will change colour!
</div>
<script type="text/javascript">
var colors = [ 255, 100, 0 ];
var hexColors = colors.invoke('toColorPart');
// same as [ 'ff', '64', '00' ]
var hex = '#' + hexColors.join('');
// hex will have the value #ff6400
$('foo').setStyle({ backgroundColor : hex });
// or this can be shortened further to:
var hex = '#' + colors.invoke('toColorPart').join('');
alert(hex);
</script>
</body>
</html>

Creating Custom Enumerables

It is possible to create your own enumerated objects simply by defining a function called _each() when you create your own classes.

The Hash Object

The Hash type that Prototype provides is a very useful data type that lets you use key-based indexing of your data. That is, it is similar to an associative array in PHP.

In actual fact, it is an extension of the JavaScript "vanilla" object. However, unlike arrays, when you create a new object in JavaScript, it is not extended unless you explicitly extend it. This can be done using the $H() function.

In order to read and write values to or from a hash, you must use the get() and set() methods. Both arguments accept the key name as the first argument, while the set() method accepts the new value as the second argument.

Listing 7 shows an example of creating a normal JavaScript object, then turning it into a Hash. It also shows how to read and update hash values.

Listing 7 Creating a hash (listing-7.html)
<html>
<head>
<title>Creating a hash</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<script type="text/javascript">
// create a normal object
var person = {
name    : 'Quentin Zervaas',
country : 'Australia'
};
alert(person.name + ' is from ' + person.country);
// now turn it into a hash
var hash = $H(person);
// or use shorthand
var hash = $H({
name    : 'Quentin Zervaas',
country : 'Australia'
});
alert(hash.get('name') + ' is from ' + hash.get('country'));
hash.set('country', 'nowhere');
alert(hash.get('name') + ' is from ' + hash.get('country'));
</script>
</body>
</html>

So now that you know how to create a Hash, how do you use it? Well, all hashes have the same enumerable methods available (such as size(), each() and invoke()).

The most important thing to be aware of is that when you define an iterator callback (as we saw above when learning about each()), the argument passed to the iterator is not just the element value. Rather, it is an object with the key in the key property and the value in the value property.

Listing 8 shows an example of how to use each() with a Hash.

Listing 8 Looping over hash values (listing-8.html)
<html>
<head>
<title>Looping over hash values</title>
<script type="text/javascript" src="/js/prototype.js"></script>
</head>
<body>
<script type="text/javascript">
var hash = $H({
name    : 'Quentin Zervaas',
country : 'Australia'
});
alert('There are ' + hash.size() + ' values in this hash!');
hash.each(function(pair) {
alert(pair.key + ' has the value ' + pair.value);
});
</script>
</body>
</html>

Additionally, there are some other methods made available to hashes that you may find useful. One such example of the keys() method, which returns an array of the keys in the hash. If you were to call hash.keys() on the hash from above, an array defined as [ 'name', 'country' ] would be returned. Similarly, you can use the values() method, which will return an array of the values in the hash.

Other operations you will find useful for hashes is to check if a value exists and also to remove a value from a hash. To check if a value exists you can see if the return value is equal to undefined (an internal JavaScript constant). For example, if (hash.get('foo') == undefined) { ... }.

To remove a value from a hash, the unset() method should be used. For example, myHash.unset('foo') will remove the element with key foo from the Hash called myHash.

Summary

In this article we looked the different data types available in Prototype. A large number of new methods have been added to existing JavaScript data types to make most functionality very simple to code.

We looked extensively at enumerables and specifically, the Hash type. Enumerables are very useful and come up frequently when developing with Prototype (such as selecting elements from the Document Object Model with $$() or select()).

In the next article of "Eight Weeks of Prototype" we will look at how to handle events in Prototype. This includes both native browser events as well as how to make use of custom events in your development.

 

 

 

 


 

 
 

 

 

 

 

 

 
 
Add a Comment:
 
(You must be signed in to comment on an article. Not a member? Click here to register)
   
Title:

Comments: