質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.58%

Ajaxを使うと、Paginatorのアクティブリンクが動かなくなる?

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,004

nnafa

score 12

 前提・実現したいこと

CakePHP3でAjaxを使ったページネーションを作成しています。

 発生している問題・エラーメッセージ

「該当のソースコード」に記載したソースコードにてページネーションで不具合が発生しております
具体的には、ページネーションの現在のページを表すスタイルがページを移動しても最初のページを指したままになってしまいます
開発者ツール、CakePHPで表示されてるエラーはありません

原因が複数のコントローラーをまたいでPaginatorを使っているからだと考えました
そこで、Paginatorに何か仕掛けをする必要があると考えましたが、妙案が思いつかないため質問いたしました

 該当のソースコード

動作確認に必要そうなコントローラ、ビューファイルを追記いたしました
不足な点があれば、修正依頼を頂けると幸いです

ArticleTables.php

<?php
namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Validation\Validator;

class ArticlesTable extends Table
{
        public function initialize(array $config)
        {
                $this->addBehavior("Timestamp");
                $this->hasMany("Comments")
                    ->setDependent(true);
        }

        public function validationDefault(Validator $validator)
        {
                $validator
                        ->notEmpty("title")
                        ->requirePresence("title")
                        ->notEmpty("name")
                        ->requirePresence("name")
                        ->notEmpty("body")
                        ->maxLength("body", 140, "本文は140文字以内です。")
                        ->requirePresence("body");

                return $validator;
        }
}

CommentsTable.php

<?php
namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Validation\Validator;

class CommentsTable extends Table
{
    public function initialize(array $config)
    {
        $this->addBehavior('Timestamp');
        $this->belongsTo("Articles");
    }

    public function validationDefault(Validator $validator)
    {
        $validator
            ->notEmpty('title')
            ->requirePresence('title')
            ->notEmpty('body')
            ->requirePresence('body');

        return $validator;
    }
}

ArticleController.php

<?php
namespace App\Controller;

class ArticlesController extends AppController
{
        public $paginate = [
                'limit' => 5,
                'maxLimit' => 10
        ];

        // 省略

        public function view($id = null)
        {
                $article = $this->Articles->get($id);
                $comment = $this->Articles->Comments->newEntity();
                $query = $this->Articles->Comments->find()->where(["article_id" => $id]);
                $this->set(compact("article", "comment"));
                $this->set("comments", $this->paginate($query));
        }

CommentsController.php

<?php
namespace App\Controller;

class CommentsController extends AppController
{
        public $paginate = [
                'limit' => 5,
                'maxLimit' => 10
        ];

        public function initialize()
        {
                parent::initialize();
                $this->loadComponent('Security');
                $this->loadComponent('Paginator');
                $this->loadComponent('RequestHandler');
        }

        // 省略

        public function get()
        {
                $id = $this->request->getQuery("article_id");
                $query = $this->Comments->find()->where(["article_id" => $id]);
                $this->response->charset("UTF-8");
                $this->response->type("json");
                $response = ($this->paginate($query));
                $this->set("response", $response);
                $this->set("_serialize", ["response"]);
        }
}

view.ctp

<?php
<h1><?= h($article->title) ?></h1>
<p><?= h($article->name) ?></p>
<h1><?= h($article->title) ?></h1>
<p><?= h($article->name) ?></p>
<p><?= h($article->body) ?></p>
<p><small>Created: <?= $article->created->format(DATE_RFC850) ?></small></p>
<hr>

<?php
        echo $this->Form->create($comment, ["url" => ["controller" => "Comments", "action" => "add"]]);
        echo $this->Form->control('title');
        echo $this->Form->control('body', ['rows' => '3']);
        echo $this->Form->hidden("article_id", ["default"=>h($article->id)]);
        echo $this->Form->button(__('Save Article'));
        echo $this->Form->end();
?>
<?php if (!$comments->isEmpty()): ?>

        <?php foreach ($comments as $comment): ?>
                <?php var_dump($comment) ?>
        <?php endforeach; ?>
        <?php $this->Paginator->options([
                'url' => [
                        'controller' => 'Comments',
                        'action' => 'get'
                ]
        ]); ?>
        <ul class="pagination">
                <?= $this->Paginator->first('<<') ?>
                <?= $this->Paginator->prev('<') ?>
                <?php if (!empty($this->Paginator->numbers())): ?>
                        <?= $this->Paginator->numbers() ?>
                <?php else: ?>
                        <li><?= $this->Paginator->current("Comments") ?></li>
                <?php endif; ?>
                <?= $this->Paginator->next('>') ?>
                <?= $this->Paginator->last('>>') ?>
        </ul>
<?php else: ?>
        <p>この記事にはまだコメントがありません。</p>
<?php endif; ?>

<hr>

<div id="result">
</div>


<script>
        $(function () {
                $(".pagination a").on("click", function () {
                        $.getJSON($(this).attr("href"), { article_id: <?= $article->id ?>  }, function (data){
                                $("#result").text(data);
                                console.log(data);
                        });
                        return false;
                });
        });
</script>

Commentsテーブルの構造も記載いたします。
article_idに外部キーを用いてコメントの属する記事を参照するようにしています。

CREATE TABLE `comments` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `article_id` int(10) unsigned NOT NULL,
  `title` varchar(255) NOT NULL,
  `body` text,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `article_key` (`article_id`),
  CONSTRAINT `comments_ibfk_1` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4

 試したこと

  • getアクションをこのように変更⇒効果なし
        public function get()
        {
                $this->autoRender = false;
                $id = $this->request->getQuery("article_id");
                $query = $this->Comments->find()->where(["article_id" => $id]);
                $response = ($this->paginate($query));
                echo json_encode($response);
        }
  • jQueryでのレスポンスの受け取り方を変えてみる⇒変化なし

何かエラーに心当たりのある方がいらっしゃいましたら、教えていただけますと幸いです
よろしくお願いいたします

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • popobot

    2018/11/30 06:25 編集

    削除済み(質問を勘違いしていた...)

    キャンセル

回答 1

checkベストアンサー

+1

Ajaxで、次のコメント情報を取得しても、HTMLが書き換わるわけではないので、ページネートのアクティブリンクが移動することはありません。
jQueryなどを利用して、自分で表示を切り替える必要があります。

Ajaxではなく、ページ遷移させれば、アクティブリンクは移動させることができると思います。その場合、ArticlesControllerのviewアクションでcommentsのページネートをするような実装になるかと

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/30 22:59

    > jQueryなどを利用して、自分で表示を切り替える必要があります。
    なるほど、そこはPaginator Helperが`$this->paginate($query)`を読んでよしなにしてくれると思っていました。なのでコントローラーでの処理がおかしいのかとばかり思い込んでしまい・・・

    jQueryで書き換える際に、Paginator Helperが使えないのではと思うのですが、これもAjaxでやる場合には仕方の無いことなのでしょうか?

    キャンセル

  • 2018/12/01 07:36

    仕方ないと思います。
    Ajaxでjsonをもらう代わりに、コメント一覧+ページネート部分のHTMLを取得して、その部分のDOMを丸ごと置き換えるという方法ならPaginator Helperが使えるかもですが...

    キャンセル

  • 2018/12/01 07:41

    Ajaxでやりたいなら、「もっと見る」みたいにして、コメントを下に追加されるような処理にするとか。Vuejsなどを使ってページネートの描画はすべてjs側にやらせるとかした方がスマートかもですね

    キャンセル

  • 2018/12/01 19:20

    ご返信ありがとうございます。

    > Ajaxでやりたいなら、・・・
    確かにそのようにすればページネート部分を考えなくていいので、ページネーションを作るより作成が簡単そうです

    > Ajaxでjsonをもらう代わりに
    json形式で受け取るメリットもあまりないですし、html形式で返してしまってもいいかもしれないですね。ビューで使うヘルパーをコントローラで使ってしまうのでソースコードを読む時に違和感がある(?)かもしれませんが、アニメーションの工夫をすれば、Webページの閲覧者側の違和感はなさそうです

    > Vuejsなどを使って・・・
    Paginator Helperが使いたいならAjaxで帰ってくるhtmlにページネートを含めておく、使わなくていいなら全部自前で作るかページネート以外の方法を探すということですね

    よくよく考えれば、Paginator HelperはHTMLテンプレートを使ってマークアップを生成するだけのヘルパーなので、無理して使う利点はないのかもしれないです・・・。フレームワークが用意してくれたものはできるだけ使うべきだと思っていたのがいけなかったです

    とても勉強になりました。 このたびはお付き合い頂き、どうもありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る