How to dynamically render a field? (ajax / without reloading page)

In my frontend I have this “partial content” div with a button that, once clicked, I’d like to process the field somewhere else in the page template… hence optimizing the page since the field in question has lots of images, videos, etc.

<div class="content--partial">
  <?php echo $page->full_content()->excerpt(90, 'words') ?>
  <a href="#">Keep reading</a>
</div>

<div class="content--full">
  #### load the same field here in full, as kirbytext()
</div>

Clicking the link would process the same field as kirbytext() instead of rendering the whole thing on page load.

I’ve tried fiddling with this: Kirby ajaxed (quick and dirty) but haven’t got nowhere…

Could someone point me a way?

1.I would change the above snippet to:

<div class="content--partial">
  <?php echo $page->text()->excerpt(90, 'words') ?>
  <a class="ajax" data-target="#content--full" href="<?php echo $page->url() . '/ajax' ?>">Keep reading</a>
</div>
<div id="content--full"></div>

2.Create a route in config.php:

c::set('routes', array(
    array(
        'pattern' => '(:all)/ajax',
        'action'  => function() {
          tpl::load(kirby()->roots()->templates() . DS . 'ajax.php', array(), false );
        }
    )
));

3.Create an ajax.php template where you retrieve the content you want to insert into the empty container (extract the right page from the url or hardcode the page if it is only one) …

<?php
  echo page('abc')->text()->kt();
?>

4.Create your ajax call (the following code requires jQuery)

var target = $('.ajax').data("target");
    url = $('.ajax').attr('href');

function loadMore() {
  $.ajax({
    url: url,
    success: function(data) {
    $(target).append(data);
    }
  });
}

$('.ajax').bind('click', function(e) {
	e.preventDefault();
	loadMore(url, target);
       $(this).hide();

});
1 Like

What would I do without you @texnixe? Thank you very much :smile:

One caveat thou…

It’s indeed working if I hardcode the page’s url like:

<?php
  echo page('event/my-event-name')->my_field()->kt();
?>

But the pages are dynamic… and when I try to – like you’ve said – extract the page from the URL… nothing.

I’ve tried to use page() it returned the “home” and when I try to use uri() I get undefined function. i.e.:

<?php
  echo page()->uri()->content_full()->kt();
?>
'action' => function($uri) {

@walkerbox: Oh, I didn’t know it was as easy as that:

OK, in your config.php

c::set('routes', array(
    array(
        'pattern' => '(:all)/ajax',
        'action'  => function($uri) {
          tpl::load(kirby()->roots()->templates() . DS . 'ajax.php', array('uri' => $uri), false );
        }
    )
));

Then in your ajax.php:

<?php echo page($uri)->content_full()->kt() ; ?>

Brilliant, it worked perfectly. Thanks @walkerbox & @texnixe

I wound’t know how to solve this whatsoever… specially because these more “advanced” stuff aren’t well documented… the docs page for the tpl:load for example… it looks like it’s there for people who know what TPL stands for.

I still have no idea what it does.

For some of this stuff you kinda need to dig into the source code, or accept that you might struggle to use the kit to its full potential. But that’s what the forum is here for!

tpl::load is the class method that kirby uses to actuate your template code. The template expects data and a file. It passes the data to the file and then returns the output as default, or optionally echos it there and then (if its third variable is set to false).

Bear in mind that when you use a custom route you are overriding the default kirby processes. If you want to use normal templates then you need to return a string of a page name, a page object, or an array where the first parameter is the page, and the second the data you want to pass to that page.

Alternatively you can handle the output yourself, either by putting together a response object, or just echoing stuff directly. Ideally you would construct a response object, but that isn’t critical in this case.

3 Likes

Damn good explanation @walkerbox, thanks a lot.

It should be added to the docs IMO.