How to create a “read more” button using AJAX in a module?

I’m working on a really simple module in Drupal 8 to get the hang of things. What it does (or rather, what the page I’m asking about in this question does) is grab some data of a bunch of simple article-style entries, and display them.

What I would like to be able to do is to have it only display the first few (say, 5), and then have a “Read more” button, which uses AJAX to display the next 5, lengthening the page so it now shows 10.

Here is the controller as I have it at the moment. The routing.yml file points to MyController::build. For the sake of simplicity, I’ve left out exactly how it gets things from the database, and some simple processing (in particular, image gets converted from a managed_file in the database into a URL to the image).

class MyController extends ControllerBase {    public function build() {     $  stuff = $  this->getStuff();     return array(       '#theme' => 'my_theme',       '#stuff' => $  stuff,       '#attached' => array(         'library' => array(           'my_theme/style',           'my_theme/readmore',         ),       ),     );   }    private function getStuff() {     $  stuff = getStuffFromDatabase();     $  result = array();     foreach($  stuff as $  key => $  item) {       $  tmp = new \stdClass();       $  tmp->id = $  item->id;       $  tmp->title = $  item->title;       $  tmp->description = $  item->description;       $  tmp->image = $  item->image;       $  result[] = $  tmp;     }   } } 

Which then gets sent to a template file:

<section>   <ul>     {% for item in stuff %}       <li>         <h3><a href="stuff/{{ item.id }}">{{ item.title }}</a></h3>         {% if item.image is not empty %}           <a href="stuff/{{ item.id }}">             <img src="{{ item.image }}" />           </a>         {% endif %}         {% if item.description is not empty %}           <p>{{ item.description }}</p>         {% endif %}       </li>     {% endfor %}   </ul> </section> <form method="post" action="" onsubmit="readmore()">   <button name="read-more" type="submit">Read more</button> </form> 

What I want is a way to change this set up so that at first the controller only sends a few of the entries, but when the button is pushed, it sends the next few, and the template displays the new ones as well as the old.

Thanks


Okay, I think I may have worked out to at least make a start on this problem. I’ve followed this tutorial, and want to get a small message displaying at the bottom, to at least get a feel for how Ajax works with Drupal 8. I’ve added

<div id="current-msg">   <h2></h2>   <p></p> </div> 

to the bottom of the .html.twig file.

I created a file identical to his ReadMessageCommand.php, except named mine MyMessageCommand.php (and renamed the class inside it accordingly). The function render has myMessage in place of readMessage.

I added a method called myMessageCallback into MyController, which works the same as in that guide, but with my_module_load_message and MyMessageCommand in the appropriate places.

To readmore.js, I added the function from the above guide, but with readMessage replaced by myMessage. I also added the following, just so I can know more easily if the function is at least being called.

console.log(response.subject); console.log(response.content); 

And I added the core/drupal.ajax dependency to the readmore library.

My question is, how do I actually get this function to be called. As far as I can tell, the guide that I’ve used has no indication of it. How to I get a message to be displayed in the div at the bottom? Once I’ve figured that out, I feel extending it so that the button acts as a “read more” shouldn’t be too much trouble.