[JavaScript]今日のエラー(解決済)
はじめに
本記事では、クレジットカード機能を実装するため、
JavaScriptファイルでコードを記述していますが、
コンソール上でエラーが発生しています。
完全に自分本位な記事で恐縮ですが、備忘録として、ここに残します。
エラー内容
商品購入をするページ(index.html.erb)に遷移後、
createアクションで購入しようとするも、
Uncaught TypeError: Cannot read property 'removeAttribute' of null
at Object.<anonymous> (card.js:26)
at (index):1
というエラーが出てしまう。
空の'removeAttribute'のプロパティは読めない。
直訳したらそう怒っているように思う。
コード
card.js
const pay = () => {
Payjp.setPublicKey("pk_test_4e8ca7835559d124aa4f5cf7");
const submit = document.getElementById("button");
submit.addEventListener("click", (e) => {
e.preventDefault();
const formResult = document.getElementById("charge-form");
const formData = new FormData(formResult);
const card = {
number: formData.get("order_form[number]"),
exp_month: formData.get("order_form[exp_month]"),
exp_year: `20${formData.get("order_form[exp_year]")}`,
cvc: formData.get("order_form[cvc]"),
};
console.log(card);
Payjp.createToken(card, (status, response) => {
if (status == 200) {
const token = response.id;
const renderDom = document.getElementById("charge-form");
const tokenObj = `<input value=${token} name='token' type="hidden">`;
renderDom.insertAdjacentHTML("beforeend", tokenObj);
}
document.getElementById("card_number").removeAttribute("name");
document.getElementById("card-exp-month").removeAttribute("name");
document.getElementById("card-exp-year").removeAttribute("name");
document.getElementById("card-cvc").removeAttribute("name");
document.getElementById("charge-form").submit();
});
});
};
window.addEventListener("load", pay);
purchase_controller.rb
class PurchasesController < ApplicationController
def index
@item = Item.find(params[:item_id])
@order_form = OrderForm.new
end
def create
@item = Item.find(params[:item_id])
@order_form = OrderForm.new(order_params)
if @order_form.valid?
pay_item
@order_form.save
redirect_to root_path
else
render :index
end
end
private
def order_params
params.require(:order_form).permit(:postal_code, :prefecture_id, :city, :address, :telephone, :building).merge(user_id: current_user.id, item_id: @item.id, token: params[:token])
end
def pay_item
Payjp.api_key = "sk_test_91d4dc8c4053b019ff2f024c"
Payjp::Charge.create(
amount: @item[:price],
card: order_params[:token],
currency: 'jpy'
)
end
end
<%= render "shared/second-header"%>
<div class='transaction-contents'>
<div class='transaction-main'>
<h1 class='transaction-title-text'>
購入内容の確認
</h1>
<%# 購入内容の表示 %>
<div class='buy-item-info'>
<%= image_tag @item.image, class: 'buy-item-img' %>
<div class='buy-item-right-content'>
<h2 class='buy-item-text'>
<%= @item.item_name %>
</h2>
<div class='buy-item-price'>
<p class='item-price-text'>¥<%= @item.price %></p>
<p class='item-price-sub-text'><%= @item.claim.name %></p>
</div>
</div>
</div>
<%# /購入内容の表示 %>
<%# 支払額の表示 %>
<div class='item-payment'>
<h1 class='item-payment-title'>
支払金額
</h1>
<p class='item-payment-price'>
¥<%= @item.price %>
</p>
</div>
<%# /支払額の表示 %>
<%= form_with id: 'charge-form',url: item_purchases_path(@item) ,model: @order_form ,class: 'transaction-form-wrap',local: true do |f| %>
<%= render 'shared/error_messages', model: f.object %>
<%# カード情報の入力 %>
<div class='credit-card-form'>
<h1 class='info-input-haedline'>
クレジットカード情報入力
</h1>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">カード情報</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :number, class:"input-default", id:"card-number", placeholder:"カード番号(半角英数字)", maxlength:"16" %>
<div class='available-card'>
<%= image_tag 'card-visa.gif', class: 'card-logo'%>
<%= image_tag 'card-mastercard.gif', class: 'card-logo'%>
<%= image_tag 'card-jcb.gif', class: 'card-logo'%>
<%= image_tag 'card-amex.gif', class: 'card-logo'%>
</div>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">有効期限</label>
<span class="indispensable">必須</span>
</div>
<div class='input-expiration-date-wrap'>
<%= f.text_area :exp_month, class:"input-expiration-date", id:"card-exp-month", placeholder:"例)3" %>
<p>月</p>
<%= f.text_area :exp_year, class:"input-expiration-date", id:"card-exp-year", placeholder:"例)23" %>
<p>年</p>
</div>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">セキュリティコード</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :cvc, class:"input-default", id:"card-cvc", placeholder:"カード背面4桁もしくは3桁の番号", maxlength:"4" %>
</div>
</div>
<%# /カード情報の入力 %>
<%# 配送先の入力 %>
<div class='shipping-address-form'>
<h1 class='info-input-haedline'>
配送先入力
</h1>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">郵便番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :postal_code, class:"input-default", id:"postal-code", placeholder:"例)123-4567", maxlength:"8" %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">都道府県</label>
<span class="indispensable">必須</span>
</div>
<%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"select-box", id:"prefecture"}) %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">市区町村</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :city, class:"input-default", id:"city", placeholder:"例)横浜市緑区"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">番地</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :address, class:"input-default", id:"addresses", placeholder:"例)青山1-1-1"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">建物名</label>
<span class="form-any">任意</span>
</div>
<%= f.text_field :building, class:"input-default", id:"building", placeholder:"例)柳ビル103"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">電話番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :telephone, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11"%>
</div>
</div>
<%# /配送先の入力 %>
<div class='buy-btn'>
<%= f.submit "購入" ,class:"buy-red-btn", id:"button" %>
</div>
<% end %>
</div>
</div>
<%= render "shared/second-footer"%>
仮説
const pay = () => {
Payjp.setPublicKey("pk_test_4e8ca7835559d124aa4f5cf7");
const submit = document.getElementById("button");
submit.addEventListener("click", (e) => {
e.preventDefault();
const formResult = document.getElementById("charge-form");
const formData = new FormData(formResult);
const card = {
number: formData.get("order_form[number]"),
exp_month: formData.get("order_form[exp_month]"),
exp_year: `20${formData.get("order_form[exp_year]")}`,
cvc: formData.get("order_form[cvc]"),
};
console.log(card);
Payjp.createToken(card, (status, response) => {
if (status == 200) {
const token = response.id;
const renderDom = document.getElementById("charge-form");
const tokenObj = `<input value=${token} name='token' type="hidden">`;
renderDom.insertAdjacentHTML("beforeend", tokenObj);
}
document.getElementById("card_number").removeAttribute("name");
document.getElementById("card-exp-month").removeAttribute("name");
document.getElementById("card-exp-year").removeAttribute("name");
document.getElementById("card-cvc").removeAttribute("name");
document.getElementById("charge-form").submit();
});
});
};
window.addEventListener("load", pay);
class PurchasesController < ApplicationController
def index
@item = Item.find(params[:item_id])
@order_form = OrderForm.new
end
def create
@item = Item.find(params[:item_id])
@order_form = OrderForm.new(order_params)
if @order_form.valid?
pay_item
@order_form.save
redirect_to root_path
else
render :index
end
end
private
def order_params
params.require(:order_form).permit(:postal_code, :prefecture_id, :city, :address, :telephone, :building).merge(user_id: current_user.id, item_id: @item.id, token: params[:token])
end
def pay_item
Payjp.api_key = "sk_test_91d4dc8c4053b019ff2f024c"
Payjp::Charge.create(
amount: @item[:price],
card: order_params[:token],
currency: 'jpy'
)
end
end
<%= render "shared/second-header"%>
<div class='transaction-contents'>
<div class='transaction-main'>
<h1 class='transaction-title-text'>
購入内容の確認
</h1>
<%# 購入内容の表示 %>
<div class='buy-item-info'>
<%= image_tag @item.image, class: 'buy-item-img' %>
<div class='buy-item-right-content'>
<h2 class='buy-item-text'>
<%= @item.item_name %>
</h2>
<div class='buy-item-price'>
<p class='item-price-text'>¥<%= @item.price %></p>
<p class='item-price-sub-text'><%= @item.claim.name %></p>
</div>
</div>
</div>
<%# /購入内容の表示 %>
<%# 支払額の表示 %>
<div class='item-payment'>
<h1 class='item-payment-title'>
支払金額
</h1>
<p class='item-payment-price'>
¥<%= @item.price %>
</p>
</div>
<%# /支払額の表示 %>
<%= form_with id: 'charge-form',url: item_purchases_path(@item) ,model: @order_form ,class: 'transaction-form-wrap',local: true do |f| %>
<%= render 'shared/error_messages', model: f.object %>
<%# カード情報の入力 %>
<div class='credit-card-form'>
<h1 class='info-input-haedline'>
クレジットカード情報入力
</h1>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">カード情報</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :number, class:"input-default", id:"card-number", placeholder:"カード番号(半角英数字)", maxlength:"16" %>
<div class='available-card'>
<%= image_tag 'card-visa.gif', class: 'card-logo'%>
<%= image_tag 'card-mastercard.gif', class: 'card-logo'%>
<%= image_tag 'card-jcb.gif', class: 'card-logo'%>
<%= image_tag 'card-amex.gif', class: 'card-logo'%>
</div>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">有効期限</label>
<span class="indispensable">必須</span>
</div>
<div class='input-expiration-date-wrap'>
<%= f.text_area :exp_month, class:"input-expiration-date", id:"card-exp-month", placeholder:"例)3" %>
<p>月</p>
<%= f.text_area :exp_year, class:"input-expiration-date", id:"card-exp-year", placeholder:"例)23" %>
<p>年</p>
</div>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">セキュリティコード</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :cvc, class:"input-default", id:"card-cvc", placeholder:"カード背面4桁もしくは3桁の番号", maxlength:"4" %>
</div>
</div>
<%# /カード情報の入力 %>
<%# 配送先の入力 %>
<div class='shipping-address-form'>
<h1 class='info-input-haedline'>
配送先入力
</h1>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">郵便番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :postal_code, class:"input-default", id:"postal-code", placeholder:"例)123-4567", maxlength:"8" %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">都道府県</label>
<span class="indispensable">必須</span>
</div>
<%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"select-box", id:"prefecture"}) %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">市区町村</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :city, class:"input-default", id:"city", placeholder:"例)横浜市緑区"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">番地</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :address, class:"input-default", id:"addresses", placeholder:"例)青山1-1-1"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">建物名</label>
<span class="form-any">任意</span>
</div>
<%= f.text_field :building, class:"input-default", id:"building", placeholder:"例)柳ビル103"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">電話番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :telephone, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11"%>
</div>
</div>
<%# /配送先の入力 %>
<div class='buy-btn'>
<%= f.submit "購入" ,class:"buy-red-btn", id:"button" %>
</div>
<% end %>
</div>
</div>
<%= render "shared/second-footer"%>
①空の'removeAttribute'のプロパティは読めない。
なら、removeAttribute
を消してしまおうか。
②送信したデータが保存されていない。ということは、コントローラーのcreateアクションの記載に誤りがある?
③モデルで各カラムたちの記述を正確にできていない?「_id」の有無。_なのか.なのか。
④ビューは画面が正確に遷移できている状態であるため、除外。ルーティングについても、問題視されておらずエラー内容を見る限り関係ないため、除外。
明日のアクション
仮説に則り、実行していく。
終わりに
未解決のため、「終わりに」ではないですが、
解決した際には、またここの記事に報告をするかと思います。
明日も楽しんでプログラミング、やっていきます!!
追記
解決しました!
内容は絶望するものでした。
document.getElementById("card_number").removeAttribute("name");
document.getElementById("card-exp-month").removeAttribute("name");
document.getElementById("card-exp-year").removeAttribute("name");
document.getElementById("card-cvc").removeAttribute("name");
card_numberではない・・・
card-number
だ・・・。
これだけです。。。
時に、コピペした方が良いこともあるのだなと、感じました。
Author And Source
この問題について([JavaScript]今日のエラー(解決済)), 我々は、より多くの情報をここで見つけました https://qiita.com/mkato1013/items/c4d7a2c13c76839dda2a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .