Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Tuesday, May 29, 2007

Maintainable JavaScript

Nicholas Zakas, now of My YAHOO!, talks about maintaining your JavaScript code. I agree with everything he says and believe this is an important video to watch.

posted by Matt Snider at 11:47 am  

Wednesday, May 23, 2007

Fun With Forms

I have been spending a lot of time improving my Form Utility Framework and wanted to share a little with you. First, we should address the reasons why we would want a Form Utility Framework. Here are some of my reasons:

  • Serialization for ajax - converts forms into key/value pair string (ex. “&key1=value1&key2=value2…”), often used with AJAX requests
  • Validation - rather than writing code to manually validate each form, i developed a system that allows you to add any number of validators for any number of fields in a form
  • Abstracted Value Retrieval - a universal method used to always retrieve the value of an input whether it is an input, a select, or a textarea HTML tag, so you do not need to remember how or worry about x-browser issues
  • Helper Methods - functions such as ones that: retrieve inputs by name, gets the first visible input of the form, disable/enable forms, etc.

Since every page will not always have a form and the Form Utility Framework will not always be used, try to keep it as lightweight as possible; it is easy to bloat your Utility with functions that you infrequently or never use.

If you find yourself using a Form Utility Framework, you might run into this problem that I had. I had not used the ‘reset’ HTMLInput type in a long time and found myself wanting to use it to clear the fields in a form. In the past that had always worked for me, but if you are using a server-side scripting language to set the values of the form fields when the page load, then you will find that reseting the form does not clear it. Instead, it reverts to the values that the form had when the page loaded. This is because in most modern browsers, when initializing a page that sets the form field value attribute, those values also are set the the fields defaultValue attribute. According to the W3C standards, the defaultValue attribute is what should be used for form reseting. Therefore, if the form fields had no values when the page load, then the reset function worked as I wanted, otherwise, it did not. To defeat this I created my own method ‘clear’ that iterates through the different form field elements and removes their values.

if (! Form) {Form = {};}
Form.clear = function(form, ingore) {
var inputs = form.getElementsByTagName('input');
// inputs
for (var i=0, input; input=inputs[i]; i++) {
if (-1 == ingore.indexOf(input.type.toLowerCase())) {
input.value = "";
if (input.checked) {input.checked = false;}
}
}
// textareas
if (-1 == ingore.indexOf('textarea')) {
inputs = form.getElementsByTagName('textarea');
for (var i=0, input; input=inputs[i]; i++) {
input.value = "";
}
}
// selects
if (-1 == ingore.indexOf('select')) {
inputs = form.getElementsByTagName('select');
for (var i=0, sel; sel=inputs[i]; i++) {
sel.selectedIndex = 0;
}
}
};

This method is pretty straight forward. Pass the method an HTMLFormElement Object and it will parse through the object’s child nodes by the tag names using the appropriate reset method. Lastly, I tossed in an array called ignore (array of string types that are not to be cleared), because I often don’t want to reset types such as “button”, “hidden”, “submit”, and “reset”. I was thinking, it might be helpful also to have a list of field names to ignore, but I did not have a need for it yet.

posted by Matt Snider at 2:13 pm  

Monday, May 21, 2007

Back from vacation

Sorry for the lack of posts last week. I was on vacation in the middle of nowhere Michigan and could not get any reception with my cellphone, which i often use as a modem when I am working remotely. Anyway, I am back now and plan to continue my series this week on Prototype vs. YUI. Also, I have decided to add a supplemental reading list, which will contain books that I have read and found useful.

posted by Matt Snider at 7:33 pm  

Friday, May 11, 2007

Opacity

Today, I experimented with the YUI Animation widget and experienced difficulty getting the opacity style to apply correctly in IE 6. It was fine in IE 7, Firefox, and Opera, but IE 6 seemed to ignore the opacity style changes. A quick web search revealed that in IE 6 opaque elements need a height and width, otherwise the opacity style will be ignored.

IE6 Opacity Filter Caveat

posted by Matt Snider at 12:38 am  

Tuesday, May 8, 2007

Prototype vs. YUI round 1: OOP Architecture

First, let’s make sure we are all using the same Frameworks, because these teams have been cranking out changes faster than you can keep up with them. This discussion will use the stable release of Prototype 1.5.1 and YUI 2.2.0. We will be analyzing the speed of creating small dummy objects to get an idea of which approach is better. Before, starting, I’d like to take a moment to thank the YUI guys for following rigorous coding standards and well documenting their code. I don’t know what high-horse the Prototype guys are riding, but there code is sloppy and it doesn’t compress well. Consequently, I have taken some time to clean up the prototype code (added semi colons, {} all statements, and ran jsmin): uncompressed and minified.

In the Prototype Framework you create Objects using the ‘Class.create()’ method. This basically attaches a function to your Object, that will execute the ‘initialize’ method you attach to the Object’s ‘prototype’ Object with all the variables you passed into the constructor. That’s a mouth full and a little hard to grasp textually, here is an example:

var PrototypeObject = Class.create();
PrototypeObject.prototype = {
initialize: function(v1, v2) {
// my initialization code
this.v1 = v1;
this.v2 = v2;
},
testFunction: function() {
alert(this.v1);
}
};
// to use
var someVariable = new PrototypeObject (v1, v2);
someVariable.testFunction();

The ’someVariable’ Object will contain all the functions and variables attached to ‘PrototypeObject.prototype’, including the initialize function. When I used this OOP Architecture, I often design the initialize function in such a way that it could be called again later to reset the object. This example illustrates how you can pass variables into the constructor and set them internally so that other function, like ‘testFunction’ can access the v1 variable, because it is attached to the ‘this’ keyword Object. You can extend these Object indefinitely, declare addition Objects inside, and do any number of customizations. However, I find that these Objects become larger than they need to be and are often difficult to follow.

In the YUI Framework you create Objects by executing a Function that contains ‘private’ like variables accessible only in the scope of the Function or through Closures in a returned Object. Again, difficult to describe textually; here is an example:

var YUIObject = function(v1, v2) {
var v1 = v1;
var v2 = v2;
return {
testFunction: function() {
alert(v1);
}
}
};
// to use
var someVariable = new YUIObject (v1, v2);
someVariable.testFunction();

So, this Object basically does the same thing as the PrototypeObject. The constructor call, instantiates the Function YUIObject, passing in two variables. Inside the scope of the Function those variables are redeclared to attach to the Function scope. Then the function returns an Object that ’someVariable’ will be set to. The ‘testFunction’ has access to v1 and v2 inside the Function scope because of Closures. For me this Architecture is easier to read and simpler to use, so I have built most of my Objects this way. The downside is that Closures leak memory like sieves in IE, if you are not careful.

To wrap up our discussion, I have created a page where you can compare the run times of the different instantiation. Unfortunately, JavaScript run-times aren’t very accurate and depend on the idle time of your computer. Having run it many times though in many browsers, I can summarize that on average the initialization of the YUI-type Objects is 35-45% faster than the Prototype Objects. Although, we’re talking about fractions of a millisecond, so you’re only going to notice this when you are creating thousands of Objects.

http://mattsnider.com/PrototypeVsYUITest.html

posted by Matt Snider at 8:20 pm  

Sunday, May 6, 2007

ExtJs

Jack Slocum, author of YAHOO.Ext, has recently launched http://extjs.com/. Initially, I thought the site was a remake of his personal site http://jackslocum.com/ with a greater focus on his YUI extension library. However, upon closer inspection, I realized the new website is dedicated also to framework interoperability. And since that is one of the main goals of this blog, I felt it worth mentioning. Anyway, Ext already works with jQuery, Prototype, and Scriptaculous.

Note: Ext is now also works standalone, without any other library. Although, I am impressed with the work this team has put into Ext, it is still to heavy for most websites. Using this Framework, it is very easy to create JavaScript libraries of 300k or more.

posted by Matt Snider at 10:12 pm  

Thursday, May 3, 2007

JavaScript Artchitecture Brief

Wow, it’s May already. I’m really busy with my full-time work at Mint and my consulting, but will find the time to post some articles. I have been working on an article to compare different features from the different Frameworks, but while experimenting with JavaScript profilers and run-time analyzers, I have not found one that I like. If you have any ideas, please comment. For now, here is a simple article on how to architect your JavaScript.

Every Unobtrusive JavaScript driven Web Application should have 3 and a half tiers:

  • 1. Framework tier
  • 2. Toolkit/Utility tier
  • 3. Business logic tier
  • 3.5 Server-client variables

Framework tier
This tier will contain the objects, functions, and resources that will be used throughout your website. I suggest packaging everything into 1 file so that your client’s browser only needs to download and cache a single file (it is more efficient to download 1 large file, than several smaller files, unless the client has enabled special browser settings). At the bare minimum a framework tier should have your Dom and Event manipulation code. I also like to add String, Object, and Array manipulators and my AJAX system. Every page of your site using JavaScript should reference your Framework tier and it is safe to use these functions in your Toolkit and Business tiers.

I use one library.js file as my Framework tier; here is an where I take several files that make up my Framework and combine them into a library.js:

cat core.js dom.js form.js string.js array.js event.js > library.js

Toolkit tier
This tier contains JavaScript tools that you only use sometimes throughout your Web Application, such as Autocomplete or Animation. These files should be included as needed throughout your site. If you find yourself using these tools on every page, then go ahead and include it in your Framework file, as it will improve site performance. Also, you may find that certain tools, like a Dialog and Animation utility are always used together; you may improve performance by combining them into one file. Generally speaking, I recommend building a utility for any code that may be used on more than 2 pages. Some utilities examples:

Autcompleter, CustomCheckbox, Dialog, Logger, Math, Slider, Tooltip, etc

Business tier
This tier will contain all page specific code. I recommend you name the file directly after your view. So, if your page is called ‘login.html’, then your JavaScript business file should be entitled ‘login.js’ (any page specific stylesheet should be named ‘login.css’ as well). These pages should be included last and can reference any Objects or Functions from the Framework and Toolkit tiers. All your events should be attached to the DOM here and I often cache frequently used DOM Elements. It is good practice to put all your Business logic inside a namespace Object, such as ‘Login’ so as to not override any variables defined in the other Tiers. For example:

var Login = function() {
var dom = {collection of dom references};
Event.addListener(dom.someElement, someEvent, someFunction);
...
}

In-page tier
This tier should actually go before the Business tier, so that the Business tier can reference Objects passes from the server. You do not need this tier if you do not use any server-side scripting language. Whenever, your server-side scripting language generates the variables, such as JSON Objects, create a script tag just prior to the Business tier reference and set any variables that you need. For examples, suppose on the login page you want to retrieve a username and a JSON object representing the user’s messages in a PHP environment:

<script type='text/javascript'>
var username = "<?= $user->getUsername() ?&gt";
var messages = <?= $user->getMessages()->toJSON() ?>
</script>
<script type='text/javascript' src='login.js'></script>

Now the username and messages variables can be referenced by the Business logic code inside ‘login.js’.

posted by Matt Snider at 3:17 pm  

Powered by WordPress