CakePHP3で通常のページネーションのように画面を再表示せず、Ajaxで一覧部分だけを切り替える方法を紹介したいと思います。
バージョン
CakePHP 3.6
画面
データ
high_schoolsテーブルに2000年以降のデータが入っています。
id | year | name | area | prefecture |
---|---|---|---|---|
1 | 2000 | 智弁和歌山 | 近畿 | 和歌山 |
2 | 2001 | 日大三 | 関東 | 東京 |
3 | 2002 | 明徳義塾 | 四国 | 高知 |
… | ||||
19 | 2018 | 大阪桐蔭 | 近畿 | 大阪 |
Controller
indexが元になる画面で、listはAjaxで一覧部分を取得するためのものです。
検索はfriendsofcake/searchで行います。
public function index()
{
$area = ['北海道' => '北海道', '東北' => '東北', '関東' => '関東', '中部' => '中部', '近畿' => '近畿', '中国' => '中国', '四国' => '四国', '九州' => '九州'];
for ($i = 2000;$i <= 2018;$i++) {
$years[$i] = $i;
}
$this->set(compact('area', 'years'));
}
public function list()
{
if ($this->request->is('ajax')) {
$this->viewBuilder()->setLayout('');
$high_schools = $this->HighSchools
->find('search', ['search' => $this->request->getQueryParams()])
->order(['year' => 'DESC']);
$high_schools = $this->paginate($high_schools);
$this->set(compact('high_schools'));
}
}
Template
index.ctpで検索部分を作ります。
jsにURLを渡しておきます。
検索ボタンはsubmitではなくただのbuttonにします。
<?php
$this->Html->script('high_schools', ['block' => true]);
$this->Html->scriptStart(['block' => true]);
echo 'var baseUrl = "'.$this->Url->build('/high-schools', false).'";';
$this->Html->scriptEnd();
?>
<h1>高校野球 歴代優勝校</h1>
<?= $this->Form->create(null, ['id'=>'search']) ?>
<label>年</label>
<?= $this->Form->select('year_from', $years, ['empty'=>true]) ?> ~ <?= $this->Form->select('year_to', $years, ['empty'=>true]) ?>
<label>地域</label>
<?= $this->Form->select('area', $area, ['empty'=>'地域を選択してください']) ?>
<?= $this->Form->button('検索', ['type'=>'button', 'id' => 'button']) ?>
<?= $this->Form->end() ?>
<div id="ajax_template"></div>
list.ctpはページネーションと一覧のみです。
<ul class="pagination">
<?php
if ($this->Paginator->hasPrev()) {
echo $this->Paginator->prev('<');
}
echo $this->Paginator->numbers();
if ($this->Paginator->hasNext()) {
echo $this->Paginator->next('>');
}
?>
</ul>
<table>
<thead>
<tr>
<th>年</th><th>高校</th><th>地域</th><th>都道府県</th>
</tr>
</thead>
<tbody>
<?php foreach($high_schools as $high_school){ ?>
<tr>
<td><?= $high_school->year ?></td>
<td><?= $high_school->name ?></td>
<td><?= $high_school->area ?></td>
<td><?= $high_school->prefecture ?></td>
</tr>
<?php } ?>
</tbody>
</table>
Model
friendsofcake/searchで検索できるようにします。
public function searchManager()
{
$searchManager = $this->behaviors()->Search->searchManager();
$searchManager
->add('year_from', 'Search.Compare', ['operator' => '>=', 'field' => 'year'])
->add('year_to', 'Search.Compare', ['operator' => '<=', 'field' => 'year'])
->value('area');
return $searchManager;
}
JavaScript
そして肝心のjsです。
Ajaxでhigh-schools/listにアクセスして、戻り値としてlist.ctpの中身を受け取り、jqueryでHTMLを書き換えています。
Ajaxのurlは検索ボタンが押下されたときは入力項目のnameとvalueから作成します。
ページネーションのリンクが押下されたときはdata属性のurlから取得しています。
あらかじめページネーションのリンクは無効にして、元のhrefの値はdata属性のurlに保持しておくのがポイントです。
$(function(){
// 検索ボタン押下時
$(document).on('click', '#button', function() {
// 検索の入力項目からurlを生成
var url = baseUrl + '/list?';
$('#search select').each(function(index, element) {
if($(this).val()){
url += $(this).attr('name') + '=' + $(this).val() + '&';
}
});
searchList(url);
});
// ページネーションのリンク押下時
$(document).on('click', '.pagination a', function() {
var url = $(this).data('url');
if(url){
searchList(url);
}
});
// 初期表示の一覧を取得するため検索ボタン押下
$('#button').click();
});
// 一覧を取得
function searchList(url){
$.ajax({
url:url,
type:'POST',
})
.done(function(data){
$('#ajax_template').html(data);
linkDisable();
});
}
// ページネーションのリンクを無効化し、data属性のurlに遷移先を保持
function linkDisable(){
$('.pagination a').each(function(index, element) {
if(!$(this).data('url')){
$(this).data('url', $(this).attr('href'));
$(this).attr('href', '#');
}
});
}