diff options
Diffstat (limited to 'guides/source/working_with_javascript_in_rails.md')
-rw-r--r-- | guides/source/working_with_javascript_in_rails.md | 119 |
1 files changed, 67 insertions, 52 deletions
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index 869490fc90..5131f809d7 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -1,3 +1,5 @@ +**DO NOT READ THIS FILE IN GITHUB, GUIDES ARE PUBLISHED IN http://guides.rubyonrails.org.** + Working with JavaScript in Rails ================================ @@ -51,7 +53,7 @@ with an id of `results`. Rails provides quite a bit of built-in support for building web pages with this technique. You rarely have to write this code yourself. The rest of this guide -will show you how Rails can help you write web sites in this manner, but it's +will show you how Rails can help you write websites in this way, but it's all built on top of this fairly simple technique. Unobtrusive JavaScript @@ -66,37 +68,38 @@ Here's the simplest way to write JavaScript. You may see it referred to as 'inline JavaScript': ```html -<a href="#" onclick="alert('Hello, world.')">Here</a> +<a href="#" onclick="this.style.backgroundColor='#990000'">Paint it red</a> ``` - -When clicked, the alert will trigger. Here's the problem: what happens when -we have lots of JavaScript we want to execute on a click? +When clicked, the link background will become red. Here's the problem: what +happens when we have lots of JavaScript we want to execute on a click? ```html -<a href="#" onclick="function fib(n){return n<2?n:fib(n-1)+fib(n-2);};alert('fib of 15 is: ' + fib(15) + '.');">Calculate</a> +<a href="#" onclick="this.style.backgroundColor='#009900';this.style.color='#FFFFFF';">Paint it green</a> ``` Awkward, right? We could pull the function definition out of the click handler, and turn it into CoffeeScript: ```coffeescript -fib = (n) -> - (if n < 2 then n else fib(n - 1) + fib(n - 2)) +paintIt = (element, backgroundColor, textColor) -> + element.style.backgroundColor = backgroundColor + if textColor? + element.style.color = textColor ``` And then on our page: ```html -<a href="#" onclick="alert('fib of 15 is: ' + fib(15) + '.');">Calculate</a> +<a href="#" onclick="paintIt(this, '#990000')">Paint it red</a> ``` That's a little bit better, but what about multiple links that have the same effect? ```html -<a href="#" onclick="alert('fib of 16 is: ' + fib(16) + '.');">Calculate</a> -<a href="#" onclick="alert('fib of 17 is: ' + fib(17) + '.');">Calculate</a> -<a href="#" onclick="alert('fib of 18 is: ' + fib(18) + '.');">Calculate</a> +<a href="#" onclick="paintIt(this, '#990000')">Paint it red</a> +<a href="#" onclick="paintIt(this, '#009900', '#FFFFFF')">Paint it green</a> +<a href="#" onclick="paintIt(this, '#000099', '#FFFFFF')">Paint it blue</a> ``` Not very DRY, eh? We can fix this by using events instead. We'll add a `data-*` @@ -104,19 +107,23 @@ attribute to our link, and then bind a handler to the click event of every link that has that attribute: ```coffeescript -fib = (n) -> - (if n < 2 then n else fib(n - 1) + fib(n - 2)) - -$(document).ready -> - $("a[data-fib]").click (e) -> - count = $(this).data("fib") - alert "fib of #{count} is: #{fib(count)}." - -... later ... - -<a href="#" data-fib="15">Calculate</a> -<a href="#" data-fib="16">Calculate</a> -<a href="#" data-fib="17">Calculate</a> +paintIt = (element, backgroundColor, textColor) -> + element.style.backgroundColor = backgroundColor + if textColor? + element.style.color = textColor + +$ -> + $("a[data-background-color]").click (e) -> + e.preventDefault() + + backgroundColor = $(this).data("background-color") + textColor = $(this).data("text-color") + paintIt(this, backgroundColor, textColor) +``` +```html +<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> ``` We call this 'unobtrusive' JavaScript because we're no longer mixing our @@ -153,7 +160,7 @@ is a helper that assists with writing forms. `form_for` takes a `:remote` option. It works like this: ```erb -<%= form_for(@post, remote: true) do |f| %> +<%= form_for(@article, remote: true) do |f| %> ... <% end %> ``` @@ -161,12 +168,12 @@ option. It works like this: This will generate the following HTML: ```html -<form accept-charset="UTF-8" action="/posts" class="new_post" data-remote="true" id="new_post" method="post"> +<form accept-charset="UTF-8" action="/articles" class="new_article" data-remote="true" id="new_article" method="post"> ... </form> ``` -Note the `data-remote='true'`. Now, the form will be submitted by Ajax rather +Note the `data-remote="true"`. Now, the form will be submitted by Ajax rather than by the browser's normal submit mechanism. You probably don't want to just sit there with a filled out `<form>`, though. @@ -175,14 +182,14 @@ bind to the `ajax:success` event. On failure, use `ajax:error`. Check it out: ```coffeescript $(document).ready -> - $("#new_post").on("ajax:success", (e, data, status, xhr) -> - $("#new_post").append xhr.responseText - ).bind "ajax:error", (e, xhr, status, error) -> - $("#new_post").append "<p>ERROR</p>" + $("#new_article").on("ajax:success", (e, data, status, xhr) -> + $("#new_article").append xhr.responseText + ).on "ajax:error", (e, xhr, status, error) -> + $("#new_article").append "<p>ERROR</p>" ``` Obviously, you'll want to be a bit more sophisticated than that, but it's a -start. +start. You can see more about the events [in the jquery-ujs wiki](https://github.com/rails/jquery-ujs/wiki/ajax). ### form_tag @@ -191,7 +198,17 @@ is very similar to `form_for`. It has a `:remote` option that you can use like this: ```erb -<%= form_tag('/posts', remote: true) %> +<%= form_tag('/articles', remote: true) do %> + ... +<% end %> +``` + +This will generate the following HTML: + +```html +<form accept-charset="UTF-8" action="/articles" data-remote="true" method="post"> + ... +</form> ``` Everything else is the same as `form_for`. See its documentation for full @@ -204,30 +221,29 @@ is a helper that assists with generating links. It has a `:remote` option you can use like this: ```erb -<%= link_to "a post", @post, remote: true %> +<%= link_to "an article", @article, remote: true %> ``` which generates ```html -<a href="/posts/1" data-remote="true">a post</a> +<a href="/articles/1" data-remote="true">an article</a> ``` You can bind to the same Ajax events as `form_for`. Here's an example. Let's -assume that we have a resource `/fib/:n` that calculates the `n`th Fibonacci -number. We would generate some HTML like this: +assume that we have a list of articles that can be deleted with just one +click. We would generate some HTML like this: ```erb -<%= link_to "Calculate", "/fib/15", remote: true, data: { fib: 15 } %> +<%= link_to "Delete article", @article, remote: true, method: :delete %> ``` and write some CoffeeScript like this: ```coffeescript -$(document).ready -> - $("a[data-fib]").on "ajax:success", (e, data, status, xhr) -> - count = $(this).data("fib") - alert "fib of #{count} is: #{data}." +$ -> + $("a[data-remote]").on "ajax:success", (e, data, status, xhr) -> + alert "The article was deleted." ``` ### button_to @@ -235,14 +251,14 @@ $(document).ready -> [`button_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to) is a helper that helps you create buttons. It has a `:remote` option that you can call like this: ```erb -<%= button_to "A post", @post, remote: true %> +<%= button_to "An article", @article, remote: true %> ``` this generates ```html -<form action="/posts/1" class="button_to" data-remote="true" method="post"> - <div><input type="submit" value="A post"></div> +<form action="/articles/1" class="button_to" data-remote="true" method="post"> + <div><input type="submit" value="An article"></div> </form> ``` @@ -276,9 +292,7 @@ The index view (`app/views/users/index.html.erb`) contains: <b>Users</b> <ul id="users"> -<% @users.each do |user| %> - <%= render user %> -<% end %> +<%= render @users %> </ul> <br> @@ -299,10 +313,10 @@ The `app/views/users/_user.html.erb` partial contains the following: The top portion of the index page displays the users. The bottom portion provides a form to create a new user. -The bottom form will call the create action on the Users controller. Because +The bottom form will call the `create` action on the `UsersController`. Because the form's remote option is set to true, the request will be posted to the -users controller as an Ajax request, looking for JavaScript. In order to -service that request, the create action of your controller would look like +`UsersController` as an Ajax request, looking for JavaScript. In order to +serve that request, the `create` action of your controller would look like this: ```ruby @@ -392,3 +406,4 @@ Here are some helpful links to help you learn even more: * [jquery-ujs list of external articles](https://github.com/rails/jquery-ujs/wiki/External-articles) * [Rails 3 Remote Links and Forms: A Definitive Guide](http://www.alfajango.com/blog/rails-3-remote-links-and-forms/) * [Railscasts: Unobtrusive JavaScript](http://railscasts.com/episodes/205-unobtrusive-javascript) +* [Railscasts: Turbolinks](http://railscasts.com/episodes/390-turbolinks) |