rails is not just ruby

Post on 06-May-2015

1.546 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Talk on Rails and JavaScript and how JavaScript should be written, structured, separated from the HTML etc.

TRANSCRIPT

Rails is not just Ruby

Software Engineer, Consultant, Trainer

http://simplabs.com

Open Source

http://github.com/marcoowhttp://github.com/simplabs

Marco Otte-Witte

JavaScript is serious

Business!

It‘s not just adding lib after

lib after lib!

Give your JavaScript the

same love your Ruby code

gets!

Know your tools!

Know your tools!

var inputs = $$('input');for (var i = 0; i < inputs.length; i++) { alert(inputs[i].name);}

Know your tools!

var inputs = $$('input');for (var i = 0; i < inputs.length; i++) { alert(inputs[i].name);} X

Know your tools!

$$('input').each(function(input) { alert(input.name);});

Protoype.js

$.each('input', function() { alert(this.name);});

jQuery

Know your tools!

function setupPage() { $('userName').update( readUserName(); );} function readUserName() { //read user's name from cookie}

Know your tools!

function setupPage() { $('userName').update( readUserName(); );} function readUserName() { //read user's name from cookie}

X

Know your tools!var Application = (function() { //private var readUserName = function() { //read user's name from cookie };

return { //public setupPage: function() { $('userName').update( readUserName(); ); }

}

})();

Know your tools!

var timeout = window.setTimeout( "element.update(" + someContent + ");", 1000);

Know your tools!

var timeout = window.setTimeout( "element.update(" + someContent + ");", 1000); X

Know your tools!

element.update.bind(element).curry( someContent).delay(1)

Protoype.js

Know your tools!

var loginField = document.getElementById('#user_login');alert(loginField.value);

Know your tools!

var loginField = document.getElementById('#user_login');alert(loginField.value);X

Know your tools!

alert($F('user_login'));Protoype.js

alert($('#user_login').val());jQuery

Know your tools!

var loginField = document.getElementById('#user_login');loginField.style.display = 'none';

Know your tools!

var loginField = document.getElementById('#user_login');loginField.style.display = 'none';X

Know your tools!

$('user_login').hide();Protoype.js

$('#user_login').hide();jQuery

Know your tools!var loginField = document.getElementById('user_login');function loginChanged() { alert(loginField.value);}if (loginField.addEventListener) { loginField.addEventListener( 'change', loginChanged, false);} else if (obj.attachEvent) { obj.attachEvent('onchange', loginChanged);}

Know your tools!var loginField = document.getElementById('user_login');function loginChanged() { alert(loginField.value);}if (loginField.addEventListener) { loginField.addEventListener( 'change', loginChanged, false);} else if (obj.attachEvent) { obj.attachEvent('onchange', loginChanged);}

X

Know your tools!

$('user_login').observe( 'change', function(event) { alert($F('user_login'));});

Protoype.js

$('#user_login').change(function() { alert(this.val());});

jQuery

Write valid JavaScript!

Write valid JavaScript!

someValue = 0;anotherValue = 1; function fun(param) { alert(param)}

Write valid JavaScript!

someValue = 0;anotherValue = 1; function fun(param) { alert(param)} X

Write valid JavaScript!

var someValue = 0;var anotherValue = 1;

function fun(param) { alert(param);}

Write valid JavaScript!

someValue = 0;anotherValue = 1; function fun(param) { alert(param)}

Write valid JavaScript!

someValue = 0;anotherValue = 1; function fun(param) { alert(param)}

Write valid JavaScript!

someValue = 0;anotherValue = 1; function fun(param) { alert(param)}

Missing semicolon.

Implied globals: someValue, anotherValue

JavaScript and Rails

JavaScript and Rails

•RESTful actions (delete, put, post)

•AJAX

•Effects

•etc.

the Demo App

the Demo App

POST/replace

the Demo App

POST/replaceCode is at http://github.com/marcoow/js-and-rails

3 possible Solutions

the classic Solution

•Helpers (remote_form_for, link_to_remote etc.)

•RJS

•onclick=“...•href=“javascript:...

the classic Solution

the classic Solution

<div id="someElement"> some text that's replaced later</div><%= link_to_remote 'Replace', :url => classic_solution_replace_path, :method => :post %>

index.html.erb

the classic Solution

class ClassicSolutionController < ApplicationController

def index end

def replace end

end

the classic Solution

page.replace_html 'someElement', :partial => 'new_content'

replace.rjs

the classic Solution

<b>Fresh new content rendered at <%= Time.now %></b><%= link_to_remote 'Replace again', :url => classic_solution_replace_path, :method => :post %>

_new_content.html.erb

•strong coupling

•hard to maintain

•no/ little code reuse

•bloated HTML

•code that actually belongs together is distributed over several places

•easy to write in the first place

the classic Solution

Full Separation

•define JavaScript controls that encapsulate all frontend logic

•mark elements with class, rel or HTML5‘s

data-* attributes

•full separation of HTML and JavaScript

•Initialization of controls on dom:loaded event

Full Separation

•define JavaScript controls that encapsulate all frontend logic

•mark elements with class, rel or HTML5‘s

data-* attributes

•full separation of HTML and JavaScript

•Initialization of controls on dom:loaded event

Full Separation

Full Separationvar Replacer = Class.create({

initialize: function(container, target) { this.container = $(container); this.target = $(target); this.container.observe('click', this.onClick.bindAsEventListener(this)); },

onClick: function(event) { event.stop(); new Ajax.Updater( this.target, this.container.href, { method: 'post', evalScripts: true } ); }

});

replacer.js

Full Separationvar Application = (function() {

var initializeReplacers = function() { $$('a[data-replaces]').each(function(replacingLink) { if (!replacingLink._initializedReplacer) { new Replacer(replacingLink, replacingLink.readAttribute('data-replaces')); replacingLink._initializedReplacer = true; } }); };

return {

setupOnLoad: function() { initializeReplacers(); },

setupOnPageUpdate: function() { initializeReplacers(); }

}

})();

application.js

Full Separation

document.observe('dom:loaded', function() { Application.setupOnLoad(); Ajax.Responders.register({ onComplete: Application.setupOnPageUpdate });});

application.js

Full Separation

document.observe('dom:loaded', function() { Application.setupOnLoad(); Ajax.Responders.register({ onComplete: Application.setupOnPageUpdate });});

application.js

Replacer controls are initialized on page load and after every AJAX request

Full Separation

<div id="someElement"> some text that's replaced later</div><%= link_to 'Replace', full_separation_replace_path, :'data-replaces' => 'someElement' %>

index.html.erb

Full Separationclass FullSeparationController < ApplicationController

def index end

def replace respond_to do |format| format.js { render :partial => 'new_content' } end end

end

Full Separation

<b>Fresh new content rendered at <%= Time.now %></b><%= link_to 'Replace again', full_separation_replace_path, :'data-replaces' => 'someElement' %>

_new_content.html.erb

•clean, semantic HTML

•full separation of concerns

•clean HTML/CSS/JS is crucial

•Behaviour is (kind of) implicit

•discipline required

Full Separation

explicit Controls

•like Full Separation

•but controls are initialized in the templates

•more explicit/ obvious what‘s going on

explicit Controls

explicit Controls

<div id="someElement"> some text that's replaced later</div><%= link_to 'Replace', controls_replace_path, :id => 'replacerLink' %><script type="text/javascript" charset="utf-8"> document.observe('dom:loaded', function() { var replacer = new Replacer('replacerLink', 'someElement'); });</script>

index.html.erb

explicit Controlsclass ControlsController < ApplicationController

def index end

def replace respond_to do |format| format.js { render :partial => 'new_content' } end end

end

explicit Controls

<b>Fresh new content rendered at <%= Time.now %></b><%= link_to 'Replace again', controls_replace_path, :id => 'secondReplacerLink' %><script type="text/javascript" charset="utf-8"> var newReplacer = new Replacer( 'secondReplacerLink', 'someElement' );</script>

_new_content.html.erb

explicit Controls

<b>Fresh new content rendered at <%= Time.now %></b><%= link_to 'Replace again', controls_replace_path, :id => 'secondReplacerLink' %><script type="text/javascript" charset="utf-8"> var newReplacer = new Replacer( 'secondReplacerLink', 'someElement' );</script>

_new_content.html.erb

No initialization on dom:loaded here as this is the result of an AJAX request (dom:loaded not fired)

•HTML is (mostly) clean and semantic

•Behaviour is explicit in the templates

•easier to grasp what‘s going on than with Full Separation

•though not as nice as full separation

explicit Controls

Either go with Full Separation

or explicit Controls!

Avoid the classic Solution when you can!

Resources

Q&A

top related