overfloweblog

are you driving me crazy?

Tuesday
Apr 1,2008

1) Detecting key events easily

How do we detect which key was pressed? Prototype provides set of
key event aliases so that we don’t have to remember that return is “13″
and escape is “27″. Almost all major keys are aliased: KEY_RETURN,
KEY_ESC, KEY_TAB, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN. See full list in API docs

$(’myInput’).observe(’keyup’, function(e){ if (e.keyCode == Event.KEY_TAB) doSomethingCoolWhenTabIsPressed(); })

2) You won’t need event capturing (most likely)

Sometimes I see capturing phase being explicitly set to false in
Event’s observe method. The good thing is that it’s set to false by
default and you would rarely need to use it. The following 2 lines are
fully identical so we can just skip this last argument:

Event.observe(’productInfo’, ‘click’, displayProductInfo, false); // ‘false’ could be skipped Event.observe(’productInfo’, ‘click’, displayProductInfo);

or a short way:

$(’productInfo’).observe(’click’, displayProductInfo, false); // ‘false’ could be skipped $(’productInfo’).observe(’click’, displayProductInfo);

3) insert() wisely

Another one of those “it’s-there-by-default” values is a position
argument of Element’s insert method. Surprisingly it’s not mentioned
anywhere in the docs - I accidentally found it wondering through the
source one day. insert accepts one of four position values: top, bottom, before, and after. If we omit this argument, it defaults to bottom (and luckily this happens to be the most common case). The following lines behave identically:

new Insertion.Bottom(’blogEntry’, new Template(’<div><h2>#{name}</h2><p>#{content}</p></div>’) .evaluate({ name: blogEntry.name, content: blogEntry.content }));   // Insertion class is deprecated - it’s recommended to use Element’s insert method:   $(’blogEntry’).insert(new Template(’<div><h2>#{name}</h2><p>#{content}</p></div>’) .evaluate({ name: blogEntry.name, content: blogEntry.content }), ‘bottom’ ); // “bottom” can be skipped   $(’blogEntry’).insert(new Template(’<div><h2>#{name}</h2><p>#{content}</p></div>’) .evaluate({ name: blogEntry.name, content: blogEntry.content }));

4) Forms gone wild

Plain form submission is quite easy but what if we want to prevent
certain elements from being serialized before submitting form via ajax?
Let’s take a look at few ways to do this:

Plain form submission using .request

$(’register’).observe(’submit’, function(e){ Event.stop(e); $(this).request(); })

Using .getInputs makes it easy to filter out elements based on type
and name attributes. In this example we’re serializing elements with
name ‘email’ and submitting result to the URI contained in form’s
“action” attribute

$(’register’).observe(’submit’, function(e){ Event.stop(e); new Ajax.Request($(this).readAttribute(’action’), { parameters: Form.serializeElements($(this).getInputs(”, ‘email’)) }) })

Using .getInputs could help most of the time but what if we want to
exclude elements that have “multiple” attribute? We might try something
like this:

$(’register’).observe(’submit’, function(e){ Event.stop(e); new Ajax.Request(this.readAttribute(’action’), { parameters: Form.serializeElements($(this).getElements() .reject(function(el){return el.hasAttribute(’multiple’)}) ); }) })

Wow, what’s going on over here?!

When submit event occurs, we prevent default submit action Event.stop(e), get all form’s elements this.getElements(), iterate over them REJECTING those that have “multiple” attribute .reject(function(el){return el.hasAttribute('multiple')}). The filtered collection is then serialized Form.serializeElements() and is submitted via ajax new Ajax.Request()

This is all very cool but here’s the reason why learning CSS3
selectors might be a good thing (the results from both - reject-based
and selector-based filtering are the same):

$(’register’).observe(’submit’, function(e){ Event.stop(e); new Ajax.Request($(this).readAttribute(’action’), { parameters: Form.serializeElements($$(’#register input:not([multiple])’)) }) })

Enjoy prototyping!

http://thinkweb2.com/projects/prototype/?p=3

How well do you know prototype?

Tuesday
Apr 1,2008


How well do you know prototype
or taking advantage of those extra 100 KB in your page

Let’s be honest - I’m tired of answering same questions over and over again. Prototype.js is a widely used javascript library with somewhat confusing online documentation. I personally find API reference to be a great resourse overall (with few glithes of course), but it’s far from being newbie-friendly. I’ve been developing with prototype for almost a year now and have been spending a lot of time on the IRC channel. It’s hard to explain what kind of nonsense people are asking sometimes. It seems to me that most of the time prototype is used at 15%, not more. I’m not surprised anymore to see Ajax.Request used with document.getElementById on one line

Here, I’ve collected most common use cases that do NOT use all of prototype’s capabilities and their simple solutions. I hope this will be a basic checklist to go through when developing for your next project. So… Here we go:

1
The wrong way:

document.getElementById(’foo’)



The right way:

$(’foo’)



Surprisingly some people actually don’t know about this one ( including ~100KB file just to use Ajax.Request family )

2
The wrong way:

var woot = document.getElementById(’bar’).value

var woot = $(’bar’).value



The right way:

var woot = $F(’bar’)



Handy shortcut for reading a value of a form control

3
The wrong way:

$(’footer’).style.height = ‘100px’;
$(’footer’).style.background = ‘#ffc’;



The right way:

$(’footer’).setStyle({
    height: ‘100px’,
    background: ‘#ffc’
})



Dreaming about IE behaving W3C way? Not happenning! (but second construct will make you forget about cross-browser glitches)

4
The wrong way:

$(’coolestWidgetEver’).innerHTML = ’some nifty content’



The right way:

$(’coolestWidgetEver’).update(’some nifty content’)



One of those simple ones yet quite often forgotten. Yes, I know they are almost the same but I want to see you doing THIS with the first one
(isn’t chaining just cool?)

$(’coolestWidgetEver’).update(’some nifty content’).addClassName(’highlight’).next().hide()



5
The wrong way:

new Ajax.Request(’ninja.php?weapon1=foo&weapon2=bar’)



The right way:

new Ajax.Request(’ninja.php’, {
    parameters: {
        weapon1: ‘foo’,
        weapon2: ‘bar’
    }
})



Cleaner and better structured parameters definition

6
The wrong way:

new Ajax.Request(’blah.php’, {
    method: ‘POST’,
    asynchronous: true,
    contentType: ‘application/x-www-form-urlencoded’,
    encoding: ‘UTF-8′,
})



The right way:

new Ajax.Request(’blah.php’)



All of these options are in Ajax.Request by default! “method: ‘POST’” happens to be on every second pastie page I’ve seen
(Still don’t believe in JS inheritance? You don’t have to. Just take advantage of it)

7
The wrong way:

Event.observe(’myContainer’, ‘click’, doSomeMagic)



The right way:

$(’myContainer’).observe(’click’, doSomeMagic)



This one is debatable but second way is more Object Oriented (well… sort of) and easier to chain (So decide for yourself)

8
The wrong way:

$$(’div.hidden’).each(function(el){
    el.show();
})



The right way:

$$(’div.hidden’).invoke(’show’)



Here’s a typical “each overuse”. We have invoke for such things, folks! Sadly not many people know about it.

9
The wrong way:

$$(’div.collapsed’).each(function(el){
    el.observe(’click’, expand);
})



The right way:

$$(’div.collapsed’).invoke(’observe’, ‘click’, expand)



Ha! Take this! Invoke can also be used for event handling when iterating over a collection of elements. It’s really easy, isn’t it?

10
The wrong way:

$$(’input.date’).invoke(’observe’, ‘focus’, onFocus);
$$(’input.date’).invoke(’observe’, ‘blur’, onBlur);



The right way:

$$(’input.date’)
    .invoke(’observe’, ‘focus’, onFocus)
        .invoke(’observe’, ‘blur’, onBlur)



Somehow people tend to forget about “chaining nirvana”. Don’t like the way it looks? Think about saving some time by NOT invoking $$ twice!

11
The wrong way:

$(’productTable’).innerHTML =
    $(’productTable’).innerHTML +
    ’<tr><td>’ + productId + ‘ ‘
    + productName + ‘</td></tr><tr><td>’
    + productId + ‘ ‘ + productPrice +
    ’</td></tr>’



The right way:

var rowTemplate = new Template(’<tr><td>#{id} #{name}</td></tr><tr><td>#{id} #{price}</td></tr>’);
$(’productTable’).insert(
    rowTemplate.evaluate({
        id: productId,
        name: productName,
        price: productPrice
    }))
)



No I’m not kidding. This has been posted to #prototype and something was wrong with it (hmm… I wonder what)
Templates are great for those nasty HTML strings. Those humongous concatenated constructs make me feel slightly nauseous
evaluate takes care of all the parsing in a nice structured way
That’s all for now. Stay tuned as there is always a room for improvement!
Created by kangax
Questions? Suggestions? Find me in #prototype [kangax] or shoot me an email [ kangax@gmail.com ]

http://thinkweb2.com/projects/prototype-checklist/