モーダルコンテンツをキャッシュしてリクエストを節約
何かしらのデータの詳細画面を、Ajaxとモーダルを利用して表示することがあると思います。
その際、1のモーダルを開く->閉じて2のモーダルを開く->再度1のモーダルを開く、といったように、
同じデータのモーダルをなんども見るときに、毎回リクエストを飛ばすのは色々と非効率だと思うので、
キャッシュするようにしたのでメモ。
なお、Laravelでは、request()->view()
で簡単にviewを返すことができるので
それを利用しています。(トレンドは、jsonを返すのでしょうが。。。)
https://laravel.com/docs/5.8/responses#other-response-types
- Laravel
- jQuery
- blade
リスト画面
list.blade.php
<table>
<tbody>
@foreach ($arr as $k = $v)
<tr>
<td>
何かしらのリスト
下のようなボタンがある。
</td>
<td>
<button type="button" class="open-modal" data-id="1">詳細を見る</button>
</td>
</tr>
@endforeach
</tbody>
</table>
{{-- モーダルコンテンツのラッパー --}}
<div id="modal">
</div>
レスポンスで返すview
modal_contents.blade.php
<div id="modal_contents">
{{dd($modalContents)}}
</div>
モーダル操作
1. モーダルを閉じるときに$('$modal_contents')
のクローンを配列にキャッシュ
※クローンを取る理由は、モーダル内で操作が行われ開いた時の状態とは変化している可能性のあるシステムであったため。
※モーダルの変化がない場合は、responseを取得した時点でキャッシュしてもいいと思います。
2. モーダルを開くときに、キャッシュされてれば、それを利用し、なければリクエストを投げる
modal.js
// モーダル開く
let openedModalContents = []; // キャッシュ用の配列
let currentId;
let canOpenModal = true;
$('.open-modal').on('click', function () {
// ダブルクリック制御
if (canOpenModal === false) {
return false;
}
canOpenModal = false;
let that = $(this);
currentId = that.data('id');
// キャッシュされていない場合
if (openedModalContents[currentId] === undefined) {
let modalContents = fetchModalContents(currentId);
modalContents.then(function (response) {
insertModalContents(response);
$('#modal').addClass('is-active');
}, function (error) {
alert(error);
});
// キャッシュされている場合
} else {
insertModalContents(openedModalContents[currentId]);
$('#modal').addClass('is-active');
}
canOpenModal = true;
});
// モーダル閉じる
$('.delete').on('click', function () {
// キャッシュする
let currentModalContents = $('#modal_comtents').clone();
openedModalContents[currentId] = currentModalContents;
$('#modal.is-active').removeClass('is-active');
});
/**
* モーダルコンテンツを取得
* @param {*} id
*/
function fetchModalContents(id) {
return new Promise(function (resolve, reject) {
$.get('api/modalContents/', {'id': id})
.done(function (data) {
resolve(data);
})
.fail(function (e) {
reject('データの取得に失敗しました。');
});
});
}
/**
* モーダルコンテンツをラッパーに挿入
*/
function insertModalContents(modalContents) {
let modalContentsWrapper = $('#modal');
modalContentsWrapper.html('');
modalContentsWrapper.html(modalContents);
}
サーバーサイドの実装。モデルは適当です。
ModalController.php
public function passModalContents(Request $request) {
$modalContents = Model::findOrFail($request->id);
return response()
->view('modal_contents', compact('modalContents'))
->header('Content-Type', 'text/html');
}
ルーティングは省略