Step.14 重頭戲:購物車的AJAX - Azraeil/JCcart_Note GitHub Wiki
fix app/views/layouts/application.html.erb
<html>
<head>
<title>JCcart</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
<%= csrf_meta_tags %>
<%= yield :header %>
</head>fix app/views/items/index.html.erb
<% content_for :header do %>
<% end %>
<h1>Listing Items</h1>
<table>
...
...
...
</table>
先寫jQuery的語法
<% content_for :header do %>
<script>
jQuery(function($){
})
</script>
<% end %>用<a>來做加入購物車的選項
<tbody>
<% @items.each do |item| %>
<tr>
...
...
<td><a href="#" class="add_cart" data-value="<%= item.id %>">加入購物車</a></td>
</tr>
<% end %>我們就能用jQuery選取器來選<a>的class add_cart
<script>
jQuery(function($){
$('.add_cart').click(function(){
});
})
</script>我們要rake routes查看網址
add_cart_item GET /items/:id/add_cart(.:format) items#add_cart
items GET /items(.:format) items#index
POST /items(.:format) items#create
new_item GET /items/new(.:format) items#new
edit_item GET /items/:id/edit(.:format) items#edit
item GET /items/:id(.:format) items#show
PATCH /items/:id(.:format) items#update
PUT /items/:id(.:format) items#update
DELETE /items/:id(.:format) items#destroy
看URI Pattern那一欄,我們剛剛談member時有說過,要從item的idd去增加購物車數量,所以我們找/items/:id/add_cart(.:format),他的HTML Verb是GET
由於我們剛剛在items_controller的add_cartaction最後是傳json,他的網址就是我們剛剛查到的/items/:id/add_cart
<script>
jQuery(function($){
$('.add_cart').click(function(){
$.getJSON('/items/:id/add_cart')
});
})
</script>不過由於:id是變數,我們要取的是item的id,也就是<a>下的data-value="<%= item.id %>"
<script>
jQuery(function($){
$('.add_cart').click(function(){
$.getJSON('/items/' + $(this).attr('data-value') + '/add_cart')
});
})
</script>我們預計會得到一個json回來,但json回來預計要更新到某一個地方
<script>
jQuery(function($){
$('.add_cart').click(function(){
$.getJSON('/items/' + $(this).attr('data-value') + '/add_cart', function(json){
})
});
})
</script>這地方就是localhost:3000/這頁上面的購物車數量:0,我們一樣用chrome工具查看
<span class="cart_counter">0</span>於是我們知道,他的class是cart_counter
於是
<script>
jQuery(function($){
$('.add_cart').click(function(){
$.getJSON('/items/' + $(this).attr('data-value') + '/add_cart', function(json){
$('#cart_counter').html();
})
});
})
</script>但我們取了的json究竟傳了什麼回來呢,我們回去看app/controllers/items_controller.rb
def add_cart
session[:cart] ||= {}
item = Item.where(:id => params[:id]).first
if item
session[:cart][item.id] ||= 0
session[:cart][item.id] += 1
end
render :json => {:counter => session[:cart].length}.to_json
endjson回傳了一個:counter的Key,對一個Value session[:cart].length。所以我們AJAX得到的json就會是
$('#cart_counter').html(json.counter);最後記得,如果不要click去觸發event,記得要用return false;
jQuery(function($){
$('.add_cart').click(function(){
$.getJSON('/items/' + $(this).attr('data-value') + '/add_cart', function(json){
$('#cart_counter').html(json.counter);
});
return false;
});
})
</script>如果沒用return false;,他會觸發<a href="#">導致我們重新讀一次這個頁面
重整頁面後,按了幾次加入購物車沒反應,重整後才發現購物車數字有增加,抓了許久蟲後發現,application.html.erb我要AJAX的span應該用#cart_counter我卻寫成.cart_counter
fix app/views/layouts/application.html.erb
from
<h1>對外頁面:public</h1>
<div>購物車數量:<span class="cart_counter"><%= get_cart_count %></span></div>to
<h1>對外頁面:public</h1>
<div>購物車數量:<span id="cart_counter"><%= get_cart_count %></span></div>我們可以debug他,把它印出來
add to app/views/layouts/application.html.erb
<h1>對外頁面:public</h1>
<div>購物車數量:<span id="cart_counter"><%= get_cart_count %></span></div>
<br>
<%= session[:cart] %>然後我們去看localhost:3000/的最上面可看到
{"1"=>9, "2"=>3, "3"=>1, "4"=>1}
從印出的畫面我們知道,session[:cart]的key是string,所以我們應該要把session[:cart]的key都轉成string
fix app/controllers/items_controller.rb
from
if item
session[:cart][item.id] ||= 0
session[:cart][item.id] += 1
endto
if item
key = item.id.to_s
session[:cart][key] ||= 0
session[:cart][key] += 1
endfix app/views/items/index.html.erb
<% content_for :header do %>
<style>
ul.items, ul.items li{
list-style: none;
padding: 0;
margin: 0;
}
</style>
<script>
...
...原本的table這寫法很醜,通常上production會拆成ul跟li
fix app/views/items/index.html.erb
from
<table>
<thead>
<tr>
<th>圖片</th>
<th>名稱</th>
<th>管理</th>
</tr>
</thead>
<tbody>
<% @items.each do |item| %>
<tr>
<td><%= image_tag item.cover.url(:icon) %></td>
<td><%= item.name %>(<%= item.price %>)</td>
<td><a href="#" class="add_cart" data-value="<%= item.id %>">加入購物車</a></td>
</tr>
<% end %>
</tbody>
</table>to
<ul class="items">
<% @items.each do |item| %>
<li>
<%= image_tag item.cover.url(:icon) %>
<span class="name"><%= item.name %>(<%= item.price %>)</span>
<a href="#" class="add_cart" data-value="<%= item.id %>">加入購物車</a>
</li>
<% end %>
</ul>接著我們繼續改CSS
<style>
ul.items, ul.items li{
list-style: none;
padding: 0;
margin: 0;
}
ul.items li{
display: block;
float: left;
border: 1px #ccc solid;
border-radius: 6px;
width: 120px;
height: 180px;
margin: 4px 0 0 4px;
text-align: center;
}
ul.items li img{
width: 120px;
height: 120px;
display: block;
border-radius: 8px;
}
ul.items li .name{
display: block;
}
ul.items li a{
display: inner-block;
background: #ccccff;
padding: 4px 8px;
border-radius: 3px;
}
</style>然後重整localhost:3000,work!!!
由於時間不夠,沒實作串金流,只有口述,請看影片2:36:24,可看 tienshunlo的筆記