Working with Javascript
in Rails
제 70회 Biweekly Lecture
2014-09-16
SeungKyun Nam
- ROR Lab. Season 3 -
Agenda
- Ajax: Introduction
- Unobtrusive Javascript
- Built-in Helpers
- Ajax: Server-Side Concerns
- Turbolinks
Ajax: Introduction
What is Ajax:
- Asynchronous
- Javascript
- and
- XML
Ajax: Introduction
The origin of the term called 'Ajax'
- by Adaptive Path
- Blog post: Ajax: A New Approach to Web Applications
- but ...
Ajax: Introduction
Understanding Request-Response Cycle
Ajax: Introduction
Classic Model vs AJax Model
Ajax: Introduction
Synchronous Model vs Asynchronous Model
Ajax: Introduction
Defining Ajax
- Presentation: XHTML and CSS -> HTML5 and CSS3
- Document Object Model
- Data: XML and XSLT -> (mostly JSON)
- Carrier: XMLHttpRequest
- Binding everything together: Javascript
Ajax: Introduction
Sample Code
// COFFEESCRIPT
$.ajax(url: "/test/lorem").done (html) ->
$("#results").append html
// Generated JAVASCRIPT
(function() {
$.ajax({
url: "/test/lorem"
}).done(function(html) {
return $("#results").append(html);
});
}).call(this);
Ajax: Introduction
Demo
Unobtrusive Javascript
Three main goals
- To separate JavaScript from HTML markup, as well as keeping modules of JavaScript independent of other modules.
- Unobtrusive JavaScript should degrade gracefully - all content should be available without all or any of the JavaScript running successfully.
- Unobtrusive JavaScript should not degrade the accessibility of the HTML, and ideally should improve it, whether the user has personal disabilities or are using an unusual, or unusually configured, browser.
Tip:
To complie CoffeeScript
without top-level function safety wrapper
# Compile the Javascript without the top-level function safety wrapper
# CoffeeScript Option -b or --bare
Tilt::CoffeeScriptTemplate.default_bare = true
config/environment.rb
Traditional Way
Inline Javascript
<a href="#" onclick="this.style.backgroundColor='#009900';this.style.color='#FFFFFF'">
Paint it green
</a>
Traditional (Better) Way
Using Functions
paintIt = (element, backgroundColor, textColor) ->
element.style.backgroundColor = backgroundColor
if textColor?
element.style.color = textColor
<a href="#" onclick="paintIt(this, '#990000')">Paint it red</a>
<a href="#" onclick="paintIt(this, '#009900', '#FFFFFF')">Paint it green</a>
Unobtrusive Way
paintIt = (element, backgroundColor, textColor) ->
element.style.backgroundColor = backgroundColor
if textColor?
element.style.color = textColor
$ ->
$("a[data-background-color]").click ->
backgroundColor = $(this).data("background-color")
textColor = $(this).data["text-color"]
paintIt(this, backgroundColor, textColor)
<a href="#" data-background-color="#990000">Paint it red</a>
<a href="#" data-background-color="#009900" data-text-color="#FFFFFF">Paint it green</a>
<a href="#" data-background-color="#000099" data-text-color="#FFFFFF">Paint it blue</a>
Unobtrusive Javascript
Demo
Built-in Helpers
Rails Ajax helpers are in two parts
- Javascript half -> rails.js
- Ruby half -> add appropriate tags to DOM
form_for
<%= form_for(@post, remote: true) do |f| %>
...
<% end %>
<!-- Generated HTML -->
<form accept-charset="UTF-8"
action="/posts"
class="new_post"
data-remote="true"
id="new_post" method="post">
...
</form>
form_for
Adding Ajax Event
$(document).ready ->
$("#new_post").on("ajax:success"), (e, data, status, xhr) ->
$("#new_post").append xhr.responseText
).bind "ajax:error", (e, data, status, error) ->
$("#new_post").append "<p>ERROR</p>"
form_tag
<%= form_tag('/posts', remote: true) %>
link_to
<%= link_to "a post", @post, remote: true %>
<!-- Generated HTML -->
<a href="/posts/1" data-remote="true">a post</a>
link_to
Adding Ajax Event
<%= link_to "Delete Post", @post, remote: true, method: :delete %>
$ ->
$("a[data-remote]").on "ajax:success", (e, data, status, xhr) ->
alert "The post was deleted."
button_to
<%= button_to "A post", @post, remote: true %>
<!-- Generated HTML -->
<form action="/posts/1" class="button_to" data-remote="true" method="post">
<div><input type="submit" value="A post"></div>
</form>
Built-in Helpers
Demo
Server-Side Concerns
Server-Side Concerns
by Example
class UsersController < ApplicationController
def index
@users = User.all
@user = User.new
end
# ...
end
<b>Users</b>
<ul id="users">
<% @users.each do |user| %>
<li><%= user.name %></li>
<% end %>
</ul>
<br>
<%= form_for(@user, remote: true) do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
app/views/users/index.html.erb
app/controllers/users_controller.rb
<li><%= user.name %></li>
app/views/users/_user.html.erb
Server-Side Concerns
by Example
# ...
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.js {}
format.json { render json: @user, status: :created, location: @user }
else
format.html { render action: "new" }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# ...
app/controllers/users_controller.rb
Server-Side Concerns
by Example
$("<%= escape_javascript(render @user) %>").appendTo("#users")
app/views/users/create.js.erb
Server-Side Concerns
Demo
Turbolinks
- Rails 4 Default
- Turbolinks Gem
- Uses Ajax to speed up page rendering
- PushState
Turbolinks
How it works
- attaches a click handler to all <a> tags
- check if browser supports PushState
- if so,
- make an Ajax request
- parse the response
- replace the entire <body>
- change the URL using PushState
PushState
a part of HTML5 History-API
<!doctype html>
<html>
<head>
<title>PushState Example</title>
<script language="javascript">
function update_history() {
var stateObj = { 'Website' : "localhost" };
window.history.pushState(stateObj, "page 2", "bar.html");
// Usage: histor.pushState(state_object, title, url)
// title -> will be currently ignored
}
</script>
</head>
<body>
<a href="#" onclick="update_history()">pushState example</a>
</body>
</html>
Using Turbolinks
# Turbolinks makes following links in your web application faster.
# Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
Gemfile
//= require turbolinks
app/assets/javascripts/applications.js
Turbolinks
To disable Turbolinks for certain links
<a href="..." data-no-turbolinks>No turbo links here</a>.
using data-no-turbolinks attribute
Turbolinks
Troubleshooting
$(document).ready ->
alert "page has loaded!"
# This event will not work because of Turbolinks
$(document).on "page:change", ->
alert "page has loaded!"
# This will work!
Turbolinks
Demo
Thank you
Copy of Working with Javascript in Rails
By Hyoseong Choi
Copy of Working with Javascript in Rails
레일스 가이드 "Working with Javascript in Rails" 강의록
- 1,307