Search code examples
javascriptphphtmljqueryyii2

call a route to load a list of data using js


I have a method in the model to search and receive messages

public function getAllMessages()
{
    $allMessages = Message::find()
        ->where(['=', 'phone', $this->phone])
        ->all();

    return $allMessages;
}

Then I display all received messages in the view

<div class="message-history">
<?php foreach ($messageModel->getAllMessages() as $index => $message) { ?>
<?php $hide = '';
if ($index > 4) {
    $hide = 'hidden';
} ?>
<div class="message <?= $hide ?>">
    <div class="panel">
        <p><?= $message->date ?></p>
        <p><?= $message->data ?></p>
    </div>
</div>
<?php } ?>
<?php if (count($messageModel->getAllMessages()) > 4) { ?>
<div class="show-all-message">
    <div class="show-all-message-btn">Show all message history</div>
</div>
<?php } ?>
</div>

As a result, I get a data page like this

$( ".show-all-message-btn" ).click(function() {
   $('.message').removeClass('hidden');
   $('.show-all-message').addClass('hidden');
});
.hidden {
  display: none;
}

.show-all-message-btn {
  cursor: pointer;
  color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="message-history">

<div class="message">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message hidden">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message hidden">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message hidden">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message hidden">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="message hidden">
    <div class="panel">
        <p>06-02-2023</p>
        <p>some message</p>
    </div>
</div>

<div class="show-all-message">
    <div class="show-all-message-btn">Show all message history</div>
</div>

</div>

The bottom line here is that when we get more than 4 messages, only the first 5 are displayed, the rest are assigned the hidden class. To show the rest, you need to click the button and they will all open

But I would like to redo all this, because 100 or more messages can be received, and it turns out that all of them will be loaded and hang on the page with the hidden class, while opening them is not a fact that you have to

I heard that I can use the offset method in php, and load the route through js, displaying 5-10 messages on the page when necessary

In php I need to do something like this

Message::find()->offset($offset)->where(['=', 'Phone', $this->phone])->all();

But how then to interact with js and make it so that initially there were 5 messages on the page, and then with each click on some button, let's say 10 messages were loaded. So that they do not initially hang on hidden on the page, but are loaded only when I need to see them


Solution

  • I think I have a simple solution for you.

    1. Pass the limit as a query parameter
    2. On page load calculate the next limit by adding 5 to the previous limit.

    Think of it as a basic pagination. A video recording of the outcome can be found here.

    The controller class looks like this:

    <?php
    
    namespace app\controllers;
    
    use yii\web\Controller;
    use app\models\Employee;
    use yii\helpers\Url;
    
    class EmployeeController extends Controller
    {
    
        public function actionIndex()
        {
            $request = \Yii::$app->request;
            $more = (int) $request->get('limit');
    
            $query = Employee::find();
            $page_size = 5;
            $limit = $more ?: 5;
    
            $employees = $query->orderBy('hire_date')
                ->limit($limit)
                ->all();
    
            return $this->render('index', [
                'employees' => $employees,
                'more_link' => Url::current(['limit' => $limit+$page_size])
            ]);
        }
    
    }
    

    and the view file looks like this

    <main class="list-container">
        <h1>Employees</h1>
        <ul>
            <?php foreach ($employees as $employee): ?>
                <li>
                    <span>
                        <?= $employee->hire_date ?>
                    </span>
                    <span>
                        <?= $employee->first_name . ' ' . $employee->last_name ?>
                    </span>
                </li>
            <?php endforeach; ?>
        </ul>
        <a href="<?= $more_link ?>" id="more-button">More</a>
    </main>
    

    For Partial Page Update (Ajax)

    <script>
        $(document).ready(function(){
            $('body').on('click', '#more-button', function(event) {
                event.preventDefault();
                const moreLink = $('#more-button').attr('href')
                $(".list-container").load( moreLink + " .list-container > * " );
            })
        })
    </script>