Prajwal Tuladhar’s Blog
 
programming, life and some random thoughts

Archive for the 'PrototypeJS' Category

Mar 29 2009

Custom event handling with Prototype

The maturity and development of JavaScript has certainly led to more efficient handling nowadays. Remember those days when IE and Netscape had different event handling mechanisms. Well, the event handling mechanism is still different in IE and non-IE browsers, the popularity of JS libraries like Prototype, jQuery, YUI have certainly helped the web developers to fill that gap. One of the main reasons I love to use these libraries (PrototypsJS especially) is that native event handling really sucks. Forget about custom events, just in order to implement event in unobstrsuive way without those libraries you would require to consider event objects differently for IE and non-IE browsers something like this:


document.getElementsByTagName("input")[0].onkeypress = function(e)	{
	// If no event object exists, then grab the global (IE-only) one
	e = e || window.event;
	return e.keyCode != 13;		//Do nothing when Enter is pressed
}

Its just a simple tiny example but one can imagine the potential complexity that could arise in nowadays’ site with petty high use of JS.

I did know that custom event handling exist in Prototype but I believe in YAGNI and never realized its potential. But as I am working in a project with massive JS and Ajax use, finally I have seen and used how custom events can be used to invoke to control encapsulate built-in JS events and use them in quite a flexible way.

While searching on the web about thistopic I found some really nice articles.

This last article has tried to explain normal and cusom events as:

When we describe normal events to our peers as a series of interactions, we generally say something like “For this tab menu, I want to swap the colors, then change the message on ‘click’ of the tab.”. Or if that sounds too awkward. We’ll say “When the user ‘clicks’ on the tab, I want to swap the colors and change the message.”

I can see it swindling in your brain already. Sure enough, the first thing that would normally come to a scripters mind is…. “I’ll assign a ‘click’ event to the tab that fires a function which will swap the colors, then change the message”. Fair enough. That totally works and that’s the way most people do it.

A custom event in this same model can be something you, yes you, get to make up. Looking at our tab/click/swapColor/changeMessage illustration, we can easily turn this into an event called onTabChange. In return, anytime our tab menu changes state, we can notify our listeners/subscribers that this event occured; then do whatever the heck we want on the fly.

Just following the above explanation, I have come with a simple example: A test scenario where a check box determines whether to enable or disable the onchange events for elements with CSS like .input. When the checkbox is enabled, particular onchange event for particular elements are also enabled and vice-versa.

Here is the HTML Code:


<fieldset>
	<legend>
		JS Custom Events
	</legend>
	<div>
		<input type="checkbox" value="1" id="enableInputEvents" />&nbsp;Enable events for text box and combo box<br/>
	</div>
	<div id="inputs_elements">
		Text Box 1:&nbsp;<input type="text" id="textbox1" value="" class="input" /><br/>
		Text Box 2:&nbsp;<input type="text" id="textbox2" value="" /><br/>
		Select Search Engine: <select id="search-engine-selector" class="input">
			<option value="">Go to</option>
			<option value="http://www.google.com">Google</option>
			<option value="http://www.yahoo.com">Yahoo!</option>
			<option value="http://www.live.com">Live</option>
		</select>
	</div>
</fieldset>

And JavaScript code for firing custom events:


Event.observe(document, 'dom:loaded', function()	{
	$('enableInputEvents').observe('click', function(e)	{
		document.fire('CheckBox:Enabled', {checked: $('enableInputEvents').checked});
	});
});

document.observe('CheckBox:Enabled', function(e)	{
	Event.stop(e);
	if (e.memo.checked)	{
		console.log("all elements with CSS class input are ENABLED");
		$$('.input').each(function(t)	{
			t.observe('change', function()	{
				alert(t.value);
			});
		});
	}
	else	{
		console.log("all elements with CSS class input are DISABLED");
		$$('.input').invoke('stopObserving');
	}
});

Custom event handling in Prototype is a bit different than other JS libraries. And CheckBox:Enabled is a special notation type for firing custom events. Prototype API call this notation as namespace:eventname o avoid custom event names conflicting with non-standard native DOM events such as mousewheel and DOMMouseScroll.

When the Checkbox is enabled

When the Checkbox is disabled


Comments Off

Mar 28 2009

Flexible function call in JavaScript

If you have used popular JavaScript libraries like PrototypeJS, jQuery and so on (I have used only PrototypeJS and Adobe Spry), you may have noticed the flexibility of calling their API class and methods. Something like this while using PrototyeJS AJAX API:


new Ajax.Request(url, {
	onSuccess: function(response)	{
		//do something
	}
	onException: function(response, exception)	{
		//do something
	}
	onFailure: function()	{
		//do something
	}
});

I have figured out that creating a method that can handle such call is certainly not so hard and in my opinion, it does provide some level of flexibility in the code.
Here is the same code:


function clickIt(options)	{
	this.message = "";
	this.afterClick = function()	{};

	for (var key in options) {
        this[key] = options[key];
    }

	this._execute = function()	{
		alert(this.message);
		this.afterClick();
	}

	this._execute();
}

The above method accepts a single object as an argument with two properties: message and afterClick and this._execute() is a kinda private method (JavaScript does not have an explicit access modifier). Now to call the above function:


Event.observe(window, 'load', function()	{
	$('iclick').observe('click', function(e)	{
		Event.stop(e);
		new clickIt({
			message: "This is some message",
			afterClick: function()	{
				if (confirm("Are you sure"))	{
					window.location.replace(this.href);
				}
			}
		});
	});
});

Since {} is regarded as object in JavaScript so one can use it to make a function/class more flexible and extensible. But since, users calling this class will have no knowledge what arguments are acceptable so, documentation plays crucial role (If you are creating an API then, the success and usability of that API heavily depends on the quality of documentation that acts as valid contract between interface and implementation code).


Comments Off

Jul 12 2008

Using JSON with Prototype

Ajax stands for Asynchronous Javascript and XML. It is an amalgamation of both new and old technologies – old because it uses already existing technologies and new because it integrates these existing technologies that few considered previously. Ajax is a technology that complements Web 2.0 and the integration of many web services at once.

Though ‘x’ of Ajax stands for XML, instead of XML another format has been gaining wide acceptance and momentum as a medium for information interchange which is called JSON aka JavaScript Object Notation. JSON is an open format describing how to represent JavaScript objects in a simple text representation that can be easily created and parsed. In other words, one can send data to the browser encoding as JSON objects instead of XML, and the JSON objects can be converted easily into JavaScript objects. Three major advantages of JSON:
1. No manual parsing necessary because JSON itself is an object whereas XML is typeless.
2. JSON frees us from having to parse data. DOM manipulation is not necessary with JSON.
3. The physical size of JSON data is less than that of XML. That is why JSON is also called “Fatless XML”.

XML Data Format

&lt;Students&gt;
&lt;Student&gt;
&lt;Name&gt;Pajwal Tuladhar&lt;/Name&gt;
&lt;Faculty&gt;BIM&lt;/Falculty&gt;
&lt;GPA&gt;3.52&lt;/GPA&gt;
&lt;Age&gt;22&lt;/Age&gt;
&lt;/Student&gt;
&lt;/Students&gt;

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

JSON Data Format

{<span class="str">"Students"</span>:[
{<span class="str">"Name"</span>:<span class="str">"Prajwal Tuladhar"</span>,<span class="str">"Faculty"</span>:<span class="str">"BIM"</span>,<span class="str">"GPA"</span>:<span class="str">"3.52"</span>,<span class="str">"Age"</span>:<span class="str">"22"</span>},
{<span class="str">"Name"</span>:<span class="str">"Max Payne"</span>,<span class="str">"Faculty"</span>:<span class="str">"MBA"</span>,<span class="str">"GPA"</span>:<span class="str">"3.90"</span>,<span class="str">"Age"</span>:<span class="str">"25"</span>},
{<span class="str">"Name"</span>:<span class="str">"Ada Lovelace"</span>,<span class="str">"Faculty"</span>:<span class="str">"BBA"</span>,<span class="str">"GPA"</span>:3.25,<span class="str">"Age"</span>:22}
]}

Lets Code

Ajax.html file

<span class="kwrd">&lt;!</span><span class="html">DOCTYPE</span> <span class="attr">html</span> <span class="attr">PUBLIC</span> <span class="kwrd">"-//W3C//DTD HTML 4.01 Transitional//EN"</span> <span class="kwrd">"http://www.w3.org/TR/html4/loose.dtd"</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">html</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">head</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">meta</span> <span class="attr">http-equiv</span><span class="kwrd">="Content-Type"</span> <span class="attr">content</span><span class="kwrd">="text/html; charset=ISO-8859-1"</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">title</span><span class="kwrd">&gt;</span>Ajax 2<span class="kwrd">&lt;/</span><span class="html">title</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">script</span> <span class="attr">type</span><span class="kwrd">="text/javascript"</span> <span class="attr">src</span><span class="kwrd">="js/prototype.js"</span><span class="kwrd">&gt;&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span>

    &lt;script type=<span class="str">"text/javascript"</span>&gt;

        window.onload = <span class="kwrd">function</span>()    {

            $(<span class="str">'CmdMakeRequest'</span>).onclick = <span class="kwrd">function</span>()    {

                <span class="kwrd">var</span> uri = <span class="str">"data2.php"</span>;

                <span class="kwrd">new</span> Ajax.Request(uri, {

                    method : <span class="str">"post"</span>,

                    onSuccess : <span class="kwrd">function</span>(t)    {

                        <span class="kwrd">var</span> r = eval(<span class="str">'('</span> + t.responseText +<span class="str">')'</span>);

                        <span class="rem">//alert(r.Students[0].GPA);</span>

                        <span class="kwrd">var</span> e = $(<span class="str">'ResponseContainer'</span>);

                        r.Students.each(<span class="kwrd">function</span>(o)    {

                            <span class="kwrd">var</span> t = document.createElement(<span class="str">'table'</span>);

                            e.appendChild(t);

                            createTableCell(<span class="str">"Name"</span>, o.Name, t);

                            createTableCell(<span class="str">"Faculty"</span>, o.Faculty, t);

                            createTableCell(<span class="str">"GPA"</span>, o.GPA, t);

                            createTableCell(<span class="str">"Age"</span>, o.Age, t);

                            <span class="kwrd">var</span> h = document.createElement(<span class="str">"hr"</span>);

                            e.appendChild(h);

                        });

                    }

                });

            };

        };

        <span class="kwrd">function</span> createTableCell(cellKey, cellValue, t)    {

            <span class="kwrd">var</span> tr = document.createElement(<span class="str">"tr"</span>);

            <span class="kwrd">var</span> tdKey = document.createElement(<span class="str">"td"</span>);

            tdKey.appendChild(document.createTextNode(cellKey));

            tdKey.width = <span class="str">"130px"</span>;

            <span class="kwrd">var</span> tdValue = document.createElement(<span class="str">"td"</span>);

            tdValue.appendChild(document.createTextNode(cellValue));

            tr.appendChild(tdKey);

            tr.appendChild(tdValue);

            t.appendChild(tr);

        }

    <span class="kwrd">&lt;/</span><span class="html">script</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">style</span> <span class="attr">type</span><span class="kwrd">="text/cs"</span><span class="kwrd">&gt;</span>

        .request-container    {

            border: 1px solid red;

            padding: 10px;

            margin: 10px;

        }

        input {

            font: 14px;

            font-weight: bold;

        }

    <span class="kwrd">&lt;/</span><span class="html">style</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;/</span><span class="html">head</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">body</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="request-container"</span><span class="kwrd">&gt;</span>

        <span class="kwrd">&lt;</span><span class="html">input</span> <span class="attr">type</span><span class="kwrd">="button"</span> <span class="attr">id</span><span class="kwrd">="CmdMakeRequest"</span> <span class="attr">value</span><span class="kwrd">="Make Request"</span> <span class="kwrd">/&gt;</span>

    <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">id</span><span class="kwrd">="ResponseContainer"</span><span class="kwrd">&gt;</span><span class="attr"> </span><span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;/</span><span class="html">body</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;/</span><span class="html">html</span><span class="kwrd">&gt;</span>

data.php file

&lt;?php

    header(<span class="str">"Content-type: application/jsonrequest"</span>);

    $json_data = array(

        <span class="str">"Students"</span> =&gt; array(

            array(

                <span class="str">"Name"</span> =&gt; <span class="str">"Prajwal Tuladhar"</span>,

                <span class="str">"Faculty"</span> =&gt; <span class="str">"BIM"</span>,

                <span class="str">"GPA"</span> =&gt; <span class="str">"3.52"</span>,

                <span class="str">"Age"</span> =&gt; <span class="str">"22"</span>

            ),

            array(

                <span class="str">"Name"</span> =&gt; <span class="str">"Max Payne"</span>,

                <span class="str">"Faculty"</span> =&gt; <span class="str">"MBA"</span>,

                <span class="str">"GPA"</span> =&gt; <span class="str">"3.90"</span>,

                <span class="str">"Age"</span> =&gt; <span class="str">"25"</span>

            ),

            array(

                <span class="str">"Name"</span> =&gt; <span class="str">"Ada Lovelace"</span>,

                <span class="str">"Faculty"</span> =&gt; <span class="str">"BBA"</span>,

                <span class="str">"GPA"</span> =&gt; 3.25,

                <span class="str">"Age"</span> =&gt; 22

            )

        )

    );

    echo json_encode($json_data);

?&gt;

I have used json_encode() function to encode json data. It is available from PHP 5 or if you are using PHP 4 you can download it from here. By making simple Ajax.Request Object of prototype you can request JSON data and after evaluating it by using eval keyword it is converted into Javascript Object. I have made table to display the data. But the dynamic DOM generation of table is not working on IE (thatswhy IE sucks). But this is only a simple example of how one can use JSON in this data intensive world of web and make most of it.

json_before

Fig. Before making request

json_after

Fig. After making request

json_response

Fig. JSON Response

json_header

Fig. JSON Header

Useful Links


Comments Off

Mar 14 2008

Ajax and XML : Ajax for tables

Published by under Ajax,JavaScript,PrototypeJS

IBM DeveloperWorks has published a very nice article illustrating the use of Ajax and XML for displaying and/or working with tabular data. Prototype JS framework has been used in the article.

http://www.ibm.com/developerworks/xml/library/x-ajaxxml10/?S_TACT=105AGX54&S_CMP=B0314&ca=dnw-910


Comments Off

RSS Feed
Subscribe by email
Follow me @ Twitter