SOY Shopで非同期で商品をカートに入れたい1の続き
商品情報のところにあるカートに入れるボタンをクリックしたら、
カートに遷移せずに
非同期で現在のカートの中身を変更したい。
ということで、
今回はカートの中身の数字を非同期で変更してみます。
まずは、
ここのHTMLを修正する。
※今回は同梱されているbryonテンプレートを改変する。
<!-- shop:module="common.parts.cart" --> <section id="head_cart"> <p class="head_btn"><a cms:id="cart_link"><img src="/shop/themes/common/images/btn_cart_off.png" alt="カートを見る"></a></p> <h1>現在のカートの中身</h1> <!-- cms:id="full_cart" --> <p id="sum">商品点数:<span id="soyshop_cart_item_count" cms:id="item_total">0</span> 点|小計:¥ <span id="soyshop_cart_sub_total" cms:id="cart_total">0</span></p> <!-- /cms:id="full_cart" --> <!-- cms:id="empty_cart" --> <p id="sum">商品点数:<span id="soyshop_cart_item_count">0</span> 点|小計:¥ <span id="soyshop_cart_sub_total">0</span></p> <!-- /cms:id="empty_cart" --> </section> <!-- /shop:module="common.parts.cart" -->
上のコードの様に、個数に関する箇所と金額に関する箇所を<span>で囲み、個別にidを指定する。
どちらのIDもよく見ると2つずつあるけど、
これは、cms:id="full_cart"かcms:id="empty_cart"で囲われた箇所で、
前者はカート内に一つでも商品が入っている場合に表示され、
後者はカート内に何も商品が入っていない場合に表示されるので、
実際にブラウザに表示されるのはどちらかのエリアなので、HTML上でidが重複していても問題ない。
続いて、
前回作成したJavaScriptのコードに下記の様にコードを追加する。
<script> function add_item(id,price){ //商品数とGET先のURLを後でも使える様に変数に入れておく var c = 1; var url = "/shop/cart/operation?a=add&count=" + c + "&item=" + id; xhr = new XMLHttpRequest(); xhr.open("GET",url); xhr.send(); xhr.addEventListener("load", function(){ //HTTPステータスが200でカートに商品が入ったことを確認 if(xhr.status == 200){ //現在表示されているカートの商品合計を更新 var countSpan = document.querySelector("#soyshop_cart_item_count"); countSpan.innerHTML = parseInt(countSpan.innerHTML) + c; //現在表示されているカートの商品小計を更新 var subTotalSpan = document.querySelector("#soyshop_cart_sub_total"); subTotalSpan.innerHTML = parseInt(subTotalSpan.innerHTML) + parseInt(price); } }); } </script>
xhr.addEventlistenerで非同期通信が成功した時の処理を追加する。
実際に行っていることは、
非同期通信が成功したかをHTTPステータスコードで確認し、
問題なく実行された証拠である200を確認できたら、
DOM操作でカートに付与したIDを元に数値の計算を行い再表示を行う。
これで非同期でカートの中身を表示できる様になったけど、
これだとまだ問題が残っている。
それは
そもそも非同期を許可していない場合の環境は使えないので、
許可していない環境では通常の同期(リダイレクト)を行う様に変更する。
※ついでにタイムアウトした時の処理も追加しておく
<script> function add_item(id,price){ //商品数とGET先のURLを後でも使える様に変数に入れておく var c = 1; var url = "/shop/cart/operation?a=add&count=" + c + "&item=" + id; //XMLHttpRequestが使用できない環境の場合はリダイレクト if(!window.XMLHttpRequest) { location.href = url; } xhr = new XMLHttpRequest(); xhr.open("GET",url); xhr.send(); xhr.addEventListener("load", function(){ //HTTPステータスが200でカートに商品が入ったことを確認 if(xhr.status == 200){ //現在表示されているカートの商品合計を更新 var countSpan = document.querySelector("#soyshop_cart_item_count"); countSpan.innerHTML = parseInt(countSpan.innerHTML) + c; //現在表示されているカートの商品小計を更新 var subTotalSpan = document.querySelector("#soyshop_cart_sub_total"); subTotalSpan.innerHTML = parseInt(subTotalSpan.innerHTML) + parseInt(price); } }); //タイムアウトした時対策 xhr.addEventListener("timeout", function(){ location.href = url; }); } </script>
これでどんな環境でも一応商品をカートに入れられる様になった。
あともうひとつ忘れてはならないのが、
カートに入れるボタンの連打防止の処理で、
これを追加しておかないと、
カートに入れるボタンをついついダブルクリックしてしまった時、
表示はこうなっているけど、
カート内に遷移したら、何故か商品が2点になっている。
連打防止を実装するために、
実行中フラグを追加する。
<script> //実行中であることを保持しておく変数 var isInvalid = false; function add_item(id,price){ //実行中であれば、処理をここで止める if (isInvalid) return false; //以後のクリックを無効にする(ここから実行を開始する) isInvalid = true; //商品数とGET先のURLを後でも使える様に変数に入れておく var c = 1; var url = "/shop/cart/operation?a=add&count=" + c + "&item=" + id; //XMLHttpRequestが使用できない環境の場合はリダイレクト if(!window.XMLHttpRequest) { location.href = url; } xhr = new XMLHttpRequest(); xhr.open("GET",url); xhr.send(); xhr.addEventListener("load", function(){ //HTTPステータスが200でカートに商品が入ったことを確認 if(xhr.status == 200){ //現在表示されているカートの商品合計を更新 var countSpan = document.querySelector("#soyshop_cart_item_count"); countSpan.innerHTML = parseInt(countSpan.innerHTML) + c; //現在表示されているカートの商品小計を更新 var subTotalSpan = document.querySelector("#soyshop_cart_sub_total"); subTotalSpan.innerHTML = parseInt(subTotalSpan.innerHTML) + parseInt(price); //処理が確実に終わったことを確認してから無効フラグを解除 isInvalid = false; } }); //タイムアウトした時対策 xhr.addEventListener("timeout", function(){ location.href = url; }); } </script>
ここまでで大体の機能は揃った。
あとはカートに入れるボタンを押した時に実行されたことが一目でわかる通知だけど、
それはデザインが絡んでくるのでここでは書かないことにする。
で、
ここまで書いたけど、
この機能をサイトを構築する度に書くのは面倒なので、
近々プラグインの形にでもしようかなと。