skip to Main Content

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

4

Answers


  1. Because you’re not calling an API to fetch the additional messages, you have to hold onto them somewhere in the browser. This could be in the DOM (as you’re doing now with the hidden class), or in a JS array, e.g.

    <script>
      const messages = [
    <?php foreach ($messageModel->getAllMessages() as $index => $message) { ?>
        {
          "date": "<?= $message->Date ?>",
          "data": "<?= $message->Data ?>",
        },
    <?php } ?>
      ];
    </script>
    

    Then you can add/remove the messages to the DOM as you please.

    Login or Signup to reply.
  2. Limit and offset would work for you.
    The best way would be to use Pjax. Load 5 initially and on the click you can load rest of them.

    Pjax

    A Little how to

    Login or Signup to reply.
  3. One way to achieve this is that you can save the offset value in your show-all-message-btn div using data-attr and whenever you need to load more data you can just get the offset from there and use ajax call to fetch the required rows and again update the offset in your button.

    Some changes you can do in your code :

    Your current html code :

    <div class="message-history">
    <?php foreach ($messageModel->getAllMessages() as $index => $message) { ?>
    <div class="message">
        <div class="panel">
            <p><?= $message->date ?></p>
            <p><?= $message->data ?></p>
        </div>
    </div>
    <?php } ?>
    <div class="show-all-message">
        <!--added offset here-->
        <div class="show-all-message-btn" data-offset="6">Show all message history</div>
    </div>
    </div>
    

    Your current route function :

    public function getAllMessages()
    {
        $allMessages = Message::find()
            ->where(['=', 'phone', $this->phone])
            ->limit(5) //add limit ..for initial load.. (this is just for demo)
            ->all();
         //... more codes
    }
    

    Now, you will see only 5 rows and button which has offset set to 6.Next , you need to write some jquery code which will get the offset and send to your backend code to query next 10 or more records and then append them in your UI.

    Your jquery code will somewhat look like below :

    $(".show-all-message-btn").click(function() {
    
      var offset = parseInt($(this).attr("data-offset")) //will get the offset..
      var updated_offset = offset + 10; //next 10 records
      var el = $(this);
      $.ajax({
        url: 'someurl..',
        type: 'POST',
        dataType:"JSON",
        data: {
          offset: offset,
          //pass phone number as well
        },
        success: function(data) {
          $(".message-history").append(data.html); //return the htmls and append to your history div//
          $(el).attr("data-start", updated_offset);
        }
      });
    })
    

    Now, your ajax will call some of the function in your backend there you can fetch the next 10 records and send back to UI.

    Your controller code will somewhat look like this :

    public function loadMore(//..get the request params)
    {
        $allMessages = Message::find()
            ->where(['=', 'phone', //add variable got from ajaxcall])
            ->offset(//pass here the request param which we get from ajax call)
            ->limit(10)
            ->all();
         //do for each and append the result... in some html 
        $html = "";
        foreach(//..looping..add your code ){
           $html .="//add your message div here.. "
        }
        //generate json object ..
        //add the key in json with html ..and assign $html to it.
        //send back the response 
    }
    

    *Note : This is not the actual code but, this will help you to get started .

    Login or Signup to reply.
  4. 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 appcontrollers;
    
    use yiiwebController;
    use appmodelsEmployee;
    use yiihelpersUrl;
    
    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>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search