LaravelプロジェクトでjQuery+Ajaxを利用してリロードせずに自動計算
かろうじて動くものができたので、記録。
(処理を書く場所と長ったらしい書き方はこれから見直し)
Bladeファイル(HTML)
<head>
<!-- ↓はAjax通信用に必要。jsファイルで呼び出せるように記載。-->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>○○○</title>
<!-- 必ずjsファイルを読み込む前にjQueryのCDNを記載。 -->
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script src="{{ secure_asset('js/app.js') }}"></script>
<!-- Laravelは標準でデフォルトでhttpsで通信する(?)。asset()ではHTTP通信になってしまうので、secure_asset()を利用。-->
</head>
<body>
<div>
<table>
<tbody>
<tr>
<th>税抜価格</th>
<td><input type="text" name="price_without_tax1"></td>
<td><input type="text" name="price_without_tax2"></td>
</tr>
<tr>
<th>税込価格</th>
<td><input type="text" name="price_with_tax1"></td>
<td><input type="text" name="price_with_tax2"></td>
</tr>
<tr>
<th>数量・容量</th>
<td><input type="text" name="amount1" value="1" required></td>
<td><input type="text" name="amount2" value="1" required></td>
</tr>
<tr>
<th>単価(税抜)</th>
<td name="unit_price1"></td>
<td name="unit_price2"></td>
</tr>
<tr>
<td colspan="3"><input type="button" id="calculate" value="自動計算"></td>
</tr>
</tbody>
</table>
</div>
</body>
/public/js/app.js
$(function(){
//Bladeファイルの<meta>タグの値を利用。これを書かないとLaravelの通信エラーに。
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
//最初の対象を '#calculate'にすると動かない(?)。
//同じ範囲内に変更対象とイベント対象を置き、その範囲を最初の()に記載。
$('table').on('click', '#calculate', function() {
var prices = new Object();
prices.price_without_tax1 = $('input[name="price_without_tax1"]').val();
prices.price_without_tax2 = $('input[name="price_without_tax2"]').val();
prices.price_with_tax1 = $('input[name="price_with_tax1"]').val();
prices.price_with_tax2 = $('input[name="price_with_tax2"]').val();
prices.amount1 = $('input[name="amount1"]').val();
prices.amount2 = $('input[name="amount2"]').val();
//$.postでも動作は同じらしい。記載方法が違うだけ。
$.ajax({
url: 'calculate', //データの送信先。Laravelのルートと紐づけ。
type: 'POST',
data: prices, //送信するデータは事前にObject化。
dataType: 'json' //受け取るデータのタイプ
})
.done(function(data) { //受け取ったデータを"data"と名付ける
$('input[name="price_without_tax1"]').val(data.price_without_tax1);
$('input[name="price_without_tax2"]').val(data.price_without_tax2);
$('input[name="price_with_tax1"]').val(data.price_with_tax1);
$('input[name="price_with_tax2"]').val(data.price_with_tax2);
$('input[name="amount1"]').val(data.amount1);
$('input[name="amount2"]').val(data.amount2);
$('[name="unit_price1"]').text(data.unit_price1);
$('[name="unit_price2"]').text(data.unit_price2);
})
.fail(function(data) {
var alertText = "";
//Laravelのバリデーションエラーは422 HTTPステータスコードで返ってくる
//バリデーションエラーのみ、アラートでエラーの中身を表示することに。
if (data.status === 422) {
for(var item in data.responseJSON.errors) {
alertText += data.responseJSON.errors[item] + "\n";
}
alert(alertText);
}
});
});
});
/routes/web.php
Route::post('calculate', 'CalculateController@calculate');
/app/Http/Controllers/CalculateController.php
class CalculateController extends Controller
{
public function calculate(Request $request)
{
$request->validate([
'price_without_tax1' => 'nullable|numeric|min:0',
'price_without_tax2' => 'nullable|numeric|min:0',
'price_with_tax1' => 'nullable|numeric|min:0',
'price_with_tax2' => 'nullable|numeric|min:0',
'amount1' => 'required|numeric|min:0.01',
'amount2' => 'required|numeric|min:0.01',
]);
$price_without_tax1 = $request->price_without_tax1;
$price_without_tax2 = $request->price_without_tax2;
$price_with_tax1 = $request->price_with_tax1;
$price_with_tax2 = $request->price_with_tax2;
$amount1 = $request->amount1;
$amount2 = $request->amount2;
$unit_price1;
$unit_price2;
$tax = 0.1;
if (is_null($price_without_tax1) && is_null($price_with_tax1)) {
//税抜・税込両方nullならnullのままに。
} else {
if (is_null($price_without_tax1)) {
$price_without_tax1 = $price_with_tax1 / (1 + $tax);
}
if (is_null($price_with_tax1)) {
$price_with_tax1 = $price_without_tax1 * (1 + $tax);
}
$unit_price1 = $price_without_tax1 / $amount1;
}
if (is_null($price_without_tax2) && is_null($price_with_tax2)) {
} else {
if (is_null($price_without_tax2)) {
$price_without_tax2 = $price_with_tax2 / (1 + $tax);
}
if (is_null($price_with_tax2)) {
$price_with_tax2 = $price_without_tax2 * (1 + $tax);
}
$unit_price2 = $price_without_tax2 / $amount2;
}
$data = [
'price_without_tax1' => $price_without_tax1,
'price_without_tax2' => $price_without_tax2,
'price_with_tax1' => $price_with_tax1,
'price_with_tax2' => $price_with_tax2,
'amount1' => $amount1,
'amount2' => $amount2,
'unit_price1' => $unit_price1,
'unit_price2' => $unit_price2
];
//計算した後に全値を小数点第2位四捨五入。
foreach ($data as &$value) {
$value = round($value, 1);
}
unset($value);
//response()を通さないとエラーになる。
return response()->json($data);
}
}