/

Async Actions & Toast Notifications

Fire a button's handler asynchronously with loading/success text states, and queue a toast notification from inside a hook or button function.

Loading/success text on a button

A ->button() call's before/loading/after options drive the button's text through each phase of an async click - idle, in-flight, and briefly on success - using the same spinner treatment Save/Delete already get (setButtonLoading() in core/xcrud.js):

$xcrud->button('Process', 'orderdetails_process_line', [
    'icon'    => 'fa fa-cogs',
    'confirm' => 'Process this order line?',
    'before'  => 'Process',
    'loading' => 'Processing…',
    'after'   => 'Processed ✓',
]);

See Custom Row Buttons for the full option list.

Queuing a toast

toast($message, $type = 'success') queues a message for xcrud.js's own toast-popup UI. Call it from inside a hook or button handler - not from a page's top-level PHP, since nothing reads it outside a write request:

function payments_after_insert(mixed $id, array $row, Xcrud $xcrud): void
{
    $xcrud->toast('Payment recorded.');
}

$type is a free-form string; xcrud.js recognizes 'success'/'error'/'info'/'warning' for styling/icon and falls back to 'info' for anything else, so a typo degrades to a plain-colored toast rather than silently vanishing.

Using it on a page with no grid at all

Async loading states and toasts aren't tied to a mounted $xcrud widget - Xcrud::uiAssets() loads just the current theme's CSS/JS, and core/xcrud.js exposes window.Xcrud.setButtonLoading()/window.Xcrud.toast() directly, so a widget-less page can reuse the exact same spinner/toast treatment on its own plain button:

<body>
    <?php echo Xcrud::uiAssets(); ?>
    <script src="core/xcrud.js"></script>

    <button type="button" id="demo-async-btn">Generate Report</button>

    <script>
        var btn = document.getElementById('demo-async-btn');

        btn.addEventListener('click', function () {
            window.Xcrud.setButtonLoading(btn, true, 'Processing…', 'none');

            fetch('core/demo_async.php', { method: 'POST' })
                .then(function (res) { return res.json(); })
                .then(function (json) {
                    window.Xcrud.setButtonLoading(btn, false, '', 'none');
                    window.Xcrud.toast(json.message || 'Done.', json.success ? 'success' : 'error');
                })
                .catch(function () {
                    window.Xcrud.setButtonLoading(btn, false, '', 'none');
                    window.Xcrud.toast('Network error.', 'error');
                });
        });
    </script>
</body>

Place Xcrud::uiAssets() and the xcrud.js <script> tag in <body>, not <head> - the router's shell-wrapping extracts only the <body> contents out of a page that produces its own full HTML document, so a <head>-only asset tag never reaches the final page.

Reference

CallPurpose
window.Xcrud.setButtonLoading(btn, isLoading, loadingText, ui)Toggles a button between idle and loading state (disabled, spinner, replacement text) - the same helper Save/Delete/->button() clicks already use internally.
window.Xcrud.toast(message, type)Shows a toast popup client-side directly, without a server round trip queuing it.
$xcrud->toast($message, $type = 'success')Queues a toast server-side, from inside a hook/button function, delivered on the next response.
Xcrud::uiAssets()Emits the current theme's CSS/JS tags without mounting a widget - for a page that wants xcrud.js's helpers but has no grid.