My experience with rails has been new and delightful, save working with the front end. Rails comes packed with helper methods some that write quick and cool Ajax methods. They follow rails conventions and do not require a strong grasp of JavaScript to get in motion.
However, if you are a stickler for standards and have a passion for valid clean markup… these helpers can leave a bit to be desired. I have been in the habit of binding js events directly to elements over the element itself. It pleases me to see markup free of inline styling, event handlers and inline js scripts. The simpler and more descriptive the markup the better.
The current application I help support utilizes prototype & scriptaculous libraries. I make use of Lowpro.js to bind js events to dom elements. It provides a simple method to bind css selector elements:
Markup:
<a href="#" class="alert">Click Me</a>
Lowpro.js:
Event.addBehavior({
'a.todo:click' : function(e) {
alert('hello world!');
}
});
Here is a piece of code I worked with last night. More or less an implimintation of Jarkko Laine’s article From Ajax Helpers to lowpro.
The script binds itself to a form with the class “useSimpleDefaults” if a form element is left unpopulated, the script will populate the filed by extracting text from the title attribute. When an input’s onfocus event is triggerd, the background color wil change by toggeling the inputs class and clear the default title value from the field. When the form is submited, the default values are cleared and an ajax request is made to submit the form. The code could use a bit of refactoring, yet it provides a good example to exploring this approach.
setDefaults = Behavior.create({
initialize: function(obj) {
myforms = this.element;
myforms.writeAttribute({onsubmit: ''})
this.setFormDefaults();
var inp;
},
setFormDefaults: function(e){
var inp;
for(var i=0;i<myforms.elements.length;i++)
{
this.setDefaultValue(myforms.elements[i]);
this.setFieldHandlers(myforms.elements[i]); }
},
setDefaultValue: function(formField) {
if(formField.type == 'text')
{
$(formField.id).removeClassName('highlight');
if(formField.value=='')
{
$(formField.id).addClassName('optional');
formField.value=formField.title;
}
}
},
setFieldHandlers: function(ff){
if( ff && ff.type == 'text')
{
ff.onfocus = function() {
if(this.type == 'text')
{
if(this.value==this.title && this.hasClassName('optional'))
{
this.value='';
$(this.id).removeClassName('optional');
}
$(this.id).addClassName('highlight');
}
}
ff.onblur = function () {
if(this.type == 'text')
{
if(this.value=='')
{
this.value=this.title;
$(this.id).addClassName('optional');
}
$(this.id).removeClassName('highlight');
}
}
}
},
clearFormDefaults: function() {
if(myforms && myforms.tagName.toLowerCase() == "form")
{
for(var i=0;i<myforms.elements.length;i++)
{
inp = myforms.elements[i];
if( inp.type == 'text' && inp.title == inp.value) {
inp.value = '';
}
}
}
},
onsubmit: function() {
this.clearFormDefaults();
this.sendRequest();
return false;
},
oncomplete: function() {
Event.addBehavior.reload();
},
sendRequest:function() {
new Ajax.Request(this.element.action, {asynchronous:true,
evalScripts:true, method:'put', parameters:
Form.serialize(myforms) +'&authenticity_token=' + encodeURIComponent( window._token ) });
}
});
Event.addBehavior({
'form.useSimpleDefaults': Remote.Form,
'form.useSimpleDefaults': setDefaults
});
CSS
input.optional {color: #80AF4C; font-size:12px;font-style:italic}
input.highlight {background: #F0E3AB;}
Its tempting to rely soley on rjs and remote helper methods to do all the heavy lifting for you where js & ajax is concerned. Yet I find it a draw back having js code spread through out random views/helpers/controllers with in an application. Afterall rails champions good coding practices. And I find it easier to have all my javascript right where i can see it.