Prototype JS Framework in a nutshell. Part 1.

Here is the first part of the short courses, describing JavaScript frameworks. The first of these will be Prototype JS.

Prototype JS Framework — from scratch

A little bit of preliminary information appears in the article JavaScript Frameworks — foreword.

The purpose of this article is not to replace the documentation, but the description of the key elements of the library, which is enough for the programmer to understand the rules, and for easy start with coding.

It can also be a “cheat sheet” for already familiar with this framework.

Here we go. Let’s get the library, add to the project, and enjoy its benefits.

Tip: we can also quickly add the Prototype JS framework from CDN:

<script src="//ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js"></script>

Using the following code, we see if Prototype JS Framework is properly loaded:

if (typeof Prototype === "undefined") {
    throw new Error("This script requires Prototype JS");
}

// or simply
//if (typeof Prototype != "undefined") {
  // code here …
//}

Let’s get deeper.

The Element object

At the beginning we say about the object element, allowing operations on the elements of the document.

Example — checking if an element is visible:

function isHidden(item_name) {
    if ($(item_name).style.display == "none")
        return true;
    else return false;
}

alert(isHidden('foobar');

The element can be hidden / displayed in easy way; instead of style.display we can use show() and hide() methods:

$('element_id').hide();

The update function — updating an element:

<div id="topSecret" style="display: none;">Invisible</div>
// …
$('topSecret').update('Visible').show();

As you can see, calls of methods can easily be combined.

Utility functions of Prototype JS Framework

Time for the magic of frameworks — special functions.

The $() function — wrapped version of getElementById(), we can specify the element ID, pass the element, and refer to it.

That $() function we meet not only in the Prototype JS Framework — it’s common in other solution of this type.

Example — using the $() function:

// hide selected elements:
$('item1', 'item2', 'item3').invoke('hide');

We can type one or more names (IDs) of elements. And the invoke() method from Enumerable object is used to run the action for all listed items.

The $$() function — double $$ — allows us to select items by CSS classes:

$$('element');

Examples — using $$() function:

// refer to all 'div' elements; the same as using:
// document.getElementsByTagName('div')
$$('div');

$$('#content'); // the same as $('content'), returns an array

$$('li.foobar'); // get all 'li' elements with the class 'foobar'

Pseudo-elements (since version 1.5.1+)

That extended syntax allows us to access the various elements, using the compact syntax instead of verbose code.

Examples — using pseudo-elements:

Sample HTML structure:

<div id="content">
  <p id="par1">Test data.</p>
  <a href="www.foobar.com">Link 1</a>
  <a href="www.foo1.com" rel="nofollow">Link 2</a>
  <a href="www.foo2.com" rel="start">Link 3</a>
  <a href="#" rel="start">Link 4</a>
</div>

Handling in JavaScript and Prototype JS:

// get ownload a collection of links that are inside the element
// with id = "content", having rel attribute
$$('#content a[rel]');

// all links whose the href attribute has value = "#"
$$('a[href="#"]');

// all links inside the element
// with id = "navbar" or "content"
$$('#navbar a', '#sidebar a');

The result are large capabilities and time-saving. We only need to master the syntax of this type.

Advanced examples:

// get only text fields
$('input[type="text"]')

// all links, except (~=) those containing
// "nofollow" in rel attribute
$$('a:not([rel~=nofollow])');

// all even rows in tables
$$('table tbody > tr:nth-child(even)');

// empty div elements (without text, only white spaces, etc)
$$('div:empty');

// getting elements by the position

// all the children of 'ul' element with id = menu
$$('ul#menu > li')

// negation
$$('ul#menu li:not(.current)')

// elements without the rel attribute
$$('ul#menu a:not([rel])')

Pseudo-elements are really a great tool.

Let’s go back to further exploring of utility functions.

The $F() function

is candy ai good?

It’s used to read the value of the form element, such as input, select, etc.

Example:

// in a simple way we access a value from the list
var value = $F( "test_list_id" );

The $A() function

Copies or converts any list (e.g. childnodes), into the object of Array type, thereby allowing faster access to the individual elements of the array.

Example — using $A():

function showOptions() {
    var someNodeList = $('listEmployees').
        getElementsByTagName('option');

    var nodes = $A(someNodeList);

    nodes.each(function(node) {
        alert(node.nodeName + ': ' + node.innerHTML);
    });
}

We get a collection of data retrieved from HTML element (e.g. select field). The next example creates a collection containing paragraphs (<p>) of the document.

Example #2:

var paras = $A(document.getElementsByTagName('p'));
paras.each(Element.hide);
$(paras.last()).show();

Even more interesting may be the next function.

The $H() function

Converts an argument to hash (implements an associative array).

Example:

var testObj = { width: 100, height: 100, depth: 20 };
var testHash = $H(testObj);
var res = testHash.toQueryString();
alert(res);

Data collections and Enumerable

Again, a small break in the discussion of utility functions.

Data collections — in Prototype JS framework they inherit from Enumerable, so we can use a dedicated processing.

An example is each:

$( "a1", "b2", "c" ).each(function(item, index) {
    alert(item + " is located at index: " + index);
    item.style.width = 180;
});

So we have an iterator pleasant to use.

The $R() function

This feature gives possibility to write the ‘new’ instruction in a concise way (arguments: lowerBound, upperBound, excludeBounds):

var range = $R(20, 100, false);
range.each(function(value, index) {
    alert("Result: " + value);
});

$A($R('aa', 'ah')).join(', '); // aa, ab, ac, ad, ae, af, ag, ah
$R(0, 10, true).include(10) // false

$R(0, 10, true).each(function(value) {
    // invoked 10 times for value = 0 to 9
});

The $w() function

Converts string to array, like qw(foo bar) in Perl language:
$w(String) -> Array

Example — using $w():

$w('apples bananas kiwis') // ['apples', 'bananas', 'kiwis']

$w('ads navbar xLinks').each(Element.hide); // hide these elements

Time for something special.

Function Try.these()

It helps us with cross-browser issues (looking for the best variant).

Example — use Try.these() function:

createXMLHttp: function() {
    return Try.these(
        function() { return new XMLHttpRequest() },
        function() { return new ActiveXObject('Msxml2.XMLHTTP') },
        function() { return new ActiveXObject('Microsoft.XMLHTTP') }
    ) || false;
}

Events handling

Prototype JS Framework gives us a convenient handling of events. It bases on the Event object.

Example — event handler for the element with ID = “foobar”:

Event.observe('foobar', 'mouseover', function() {
    alert('Mouse over!');
});

We can say that we have the ‘observer’ registered here, with reaction for a specific event.

Another example is the event handler to load the document (page):

Event.observe(window, 'load', function() {
    // …
});

AJAX and Prototype JS framework

Prototype JS is an excellent framework also when it comes to supporting the work with Ajax. It isolates the level of implementation in a particular browser, giving us a hand convenient tools to work with Ajax.

Ajax.Updater — Ajax call with refresh of page element.

It has additional options:

– evalScripts (default false)

– insertion (‘top’, ‘bottom’, ‘before’, ‘after’)

Example — Ajax.Updater():

new Ajax.Updater('items', '/items', {
    parameters: { text: $F('text') },
    insertion: Insertion.Bottom
});

Example #2:

function _updateX(tmp_id) {
    new Ajax.Updater('id2', '/module/action, {
        asynchronous: true,
        evalScripts: true,
        parameters:{
            id: tmp_id
         }
    });
}

The second argument (module / action) is an address of the server-side resource that receives a request.

Defining success and failure events:

function testAjax() {
  new Ajax.Updater({ success: 'newsContent', failure: 'errors' },
    '/prototypejs/data', {
      method: 'post', insertion: Insertion.Top
  });
}

Ajax.Request — is another tool, similar to the Updater(). We will use it especially where not necessarily we want to update the page element.

Example — use of Ajax.Updater():

// ajax.js
alert('Hello!');

// call
new Ajax.Request('my_ajax.js', { method: 'get' });

Example #2:

function testAjax() {
    new Ajax.Request('/prototypejs/data', {
        method: 'get',
        onSuccess: function(transport) {
            $('news').innerHTML = transport.
                responseText || "no data";
        },
        onFailure: function() {
            alert('An error occurred')
        }
    });
}

Access to JSON

In the recent article about JSON, we wrote about the basics of working with JSON in JavaScript. Prototype JS framework has its own solutions.

Example — JSON and Prototype JS framework:

new Ajax.Request('/some_url', {
    method: 'get',
    requestHeaders: { Accept: 'application/json' },
    onSuccess: function(transport) {
        var json = transport.responseText.evalJSON(true);
    }
});

We define here a new type of the parameter: requestHeaders. It refers to the request header, in our example specifies the type of accepted data (JSON).

Passing parameters can be done as follows:

function testAjax() {
    var url = "/prototypejs/data";
    var params = new Object();

    params.method = "get";
    params.parameters = "person = John";
    params.onComplete = putText;
    params.onFailure = showErrorMsg;

    new Ajax.Request(url, params);
}

If we want to pass parameters using method POST, we use the postBody.

Example — arguments passed through postBody:

new Ajax.Request('/foo/bar', {
    method: 'post',
    postBody: 'thisvar=123&thatvar=Xyz'
});

On the other hand, the evalScripts set to true, will execute scripts in blocks <script> </script>

Example — force the execution of JS code:

newAjax.Updater('mydiv', '/foo/bar', {
    asynchronous: true,
    evalScripts: true
});

Updating part of the page periodically — PeriodicalUpdater

It’s interesting and useful solution from the creators of Prototype JS framework.

Example — the use of Ajax.PeriodicalUpdater:

function testAjax() {
    new Ajax.PeriodicalUpdater('dyn_content', '/action/data', {
        // insertion: bottom, etc…
        method: 'get', frequency: 3, decay: 2
    });
}

And at the end — an example of global definition.

Example — the Ajax.Responders

// insertion: bottom, etc …
Ajax.Responders.register({
    onCreate: showLoader,
    onComplete: hideLoader
});

Thus, we registered a function for all AJAX requests.

More (and up-to-date) information about Ajax common options available in documentation.

Summary

And we finished the first part of the course about Prototype JS framework. Next two parts will appear very soon.

Enjoy Prototype JS!