Perfection Kills

by kangax

Exploring Javascript by example

← back 536 words

How well do you know prototype (part II)

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>

#{content}
</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}

#{content}
</div>

')
    .evaluate({
      name: blogEntry.name,
      content: blogEntry.content
    }), 'bottom' ); // "bottom" can be skipped

$('blogEntry').insert(new Template('
<div>
<h2>#{name}</h2>

#{content}
</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!

Did you like this? Donations are welcome

comments powered by Disqus