Frontend disaccoppiati e CORS
Montare un widget Xcrud - o solo i suoi helper toast/spinner - da un frontend che non è affatto una pagina PHP.
window.Xcrud.mount()
Ogni widget Xcrud è, lato client, un semplice oggetto JavaScript. core/xcrud.js espone un helper globale che ne costruisce uno direttamente su un mount point, senza alcuna chiamata PHP a render():
<div id="payments-grid"></div>
<script src="core/xcrud.js"></script>
<script>
window.Xcrud.mount('payments-grid', {
route: 'payments',
api: 'https://api.example.com/core/ajax_crud.php'
});
</script>
Questa è la forma che un frontend completamente statico (un semplice file HTML, una SPA separata) usa per incorporare una griglia che dialoga con un backend xCRUD Nova Pro con cui non condivide alcun runtime PHP. Il mount point deve comunque avere già caricati gli asset del tema corrispondente - vedi Xcrud::uiAssets() nella Guida di riferimento a XcrudConfig.
Helper senza widget
La stessa globale espone anche gli helper di feedback UI che ogni griglia montata già usa internamente, così una pagina senza alcuna griglia - solo un pulsante, ad esempio - può riutilizzare esattamente lo stesso aspetto:
| Funzione | Descrizione |
|---|---|
Xcrud.toast(message, type) | Mostra la stessa notifica toast che genererebbe un'azione Salva/Elimina o una chiamata ->toast() di un hook. |
Xcrud.spinnerHtml(ui) | Restituisce il markup dello spinner del tema come stringa HTML. ui assume di default il valore predefinito di XcrudConfig::$ui ('tailwind') se omesso. |
Xcrud.setButtonLoading(btn, isLoading, loadingLabel, ui) | Alterna un pulsante tra il suo stato normale e quello di caricamento (disabilitato, spinner, eventuale sostituzione dell'etichetta) - lo stesso trattamento che ogni pulsante Salva/Elimina riceve mentre una richiesta è in corso. |
<button id="run-report">Generate Report</button>
<script>
var btn = document.getElementById('run-report');
btn.addEventListener('click', function () {
window.Xcrud.setButtonLoading(btn, true, 'Processing…');
fetch('core/demo_async.php', { method: 'POST' })
.then(function (res) { return res.json(); })
.then(function (json) {
window.Xcrud.setButtonLoading(btn, false);
window.Xcrud.toast(json.message || 'Done.', json.success ? 'success' : 'error');
});
});
</script>
Questo è esattamente il pattern usato da pages/async-demo.php - una pagina senza alcun widget $xcrud, che carica direttamente Xcrud::uiAssets() e core/xcrud.js per ottenere queste globali.
Configurazione server-side per l'uso cross-origin
Quando frontend e backend sono serviti da origini diverse, diverse impostazioni di XcrudConfig devono spostarsi dai loro valori predefiniti pensati per la stessa origine:
| Proprietà | Tipo | Descrizione |
|---|---|---|
$allowedOrigins | array | La whitelist CORS - le origini autorizzate a chiamare ajax_crud.php cross-dominio. Un'origine frontend mancante da questo elenco è la causa più comune di un "errore di rete" lato browser anche quando il backend ha risposto correttamente. |
$crossOriginSessionCookie | bool | Quando è true, imposta il cookie di sessione di login su SameSite=None; Secure in modo che sopravviva a una chiamata cross-origin fetch(..., {credentials: 'include'}). Necessario solo quando anche $loginAuthentication è attivo e il frontend è su un'origine diversa. Richiede un contesto realmente sicuro (vero HTTPS, oppure entrambi i lati su localhost/127.0.0.1). |
$forceApiUrl | string | Forza ogni widget di ogni pagina a chiamare questo URL assoluto per l'API, invece del predefinito relativo core/ajax_crud.php - necessario quando l'HTML viene servito da un'origine diversa rispetto all'API. |
$forceUploadUrl | string | Stessa idea per l'endpoint di upload. |
$forceGalleryUrl | string | Stessa idea per l'endpoint della gallery. |
$forceMediaUrl | string | Stessa idea per images_handler.php, l'endpoint firmato attraverso cui ogni file caricato viene effettivamente servito. |
public static array $allowedOrigins = ['https://app.example.com'];
public static bool $crossOriginSessionCookie = true;
public static string $forceApiUrl = 'https://api.example.com/core/ajax_crud.php';
public static string $forceUploadUrl = 'https://api.example.com/core/upload.php';
public static string $forceMediaUrl = 'https://api.example.com/core/images_handler.php';