Skip to content

AJAX lists

Open the live demo at /documentation/examples/run/lists.

Introduction

A growing table is a backend problem and a frontend problem. PHP paginates with paginate(), encrypts row ids, and returns HTML fragments. dotapp.js patches #listInner after $dotapp().load(). Row toggle and delete are buttons, not one <fo-rm> per row.

Routes

GET renders the page. POST endpoints return ajaxReply JSON for the list, save, delete, and toggle actions:

Router::get($pair($p . '/lists'), 'Examples:Lists@page!', Router::STATIC_ROUTE);
Router::post($pair($p . '/lists/list'), 'Examples:Lists@list!', Router::STATIC_ROUTE);
Router::post($pair($p . '/lists/save'), 'Examples:Lists@save!', Router::STATIC_ROUTE);
Router::post($pair($p . '/lists/delete'), 'Examples:Lists@delete!', Router::STATIC_ROUTE);
Router::post($pair($p . '/lists/toggle'), 'Examples:Lists@toggle!', Router::STATIC_ROUTE);

PHP list + pager

Search runs from three characters. Ids leave PHP as Crypto::encrypt($id, 'Examples.item.id'). Decrypt with the same extra key. Failure is === false.

$result = DB::module('RAW')->q(function ($qb) use ($q, $useSearch) {
    $qb->select(['id', 'title', 'active', 'created_at'])->from('examples_items')->orderBy('id', 'DESC');
    if ($useSearch) {
        $esc = str_replace(['\\', '%', '_'], ['\\\\', '\%', '\_'], $q);
        $qb->where('title', 'LIKE', '%' . $esc . '%');
    }
})->paginate(10, $page);

The fragment view lists-inner.view.php is what JS puts into #listInner. Return it in html next to status and message.

JavaScript

Cover the list with .ex_busy until load() finishes. Patch a child, not the overlay wrapper. Delete uses a graphical dialog — never alert() or window.confirm().

$dotapp().load(listUrl, "POST", { page: page, q: q },
  function (raw) {
    var reply = $dotapp().parseReply(raw);
    if (reply && reply.html) $dotapp("#listInner").html(reply.html);
    listDone();
  },
  function () { listDone(); }
);

The page script lives at /app/modules/Examples/assets/js/lists.js.

Live demo

/documentation/examples/run/lists needs MySQL in app/config.php. Without a database the page explains that the demo is not ready.