Frontends desacoplados y CORS
Montar un widget de Xcrud - o solo sus ayudantes de toast/spinner - desde un frontend que no es una página PHP en absoluto.
window.Xcrud.mount()
Todo widget de Xcrud es, del lado del cliente, un simple objeto JavaScript. core/xcrud.js expone un helper global que construye uno directamente sobre un punto de montaje, sin que intervenga ninguna llamada 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>
Esta es la forma que usa un frontend completamente estático (un archivo HTML plano, una SPA independiente) para incrustar una cuadrícula que se comunica con un backend de xCRUD Nova Pro con el que no comparte runtime de PHP. El punto de montaje sigue necesitando que se carguen antes los recursos del tema correspondiente - consulta Xcrud::uiAssets() en la Referencia de configuración.
Ayudantes sin widget
El mismo global también expone los ayudantes de retroalimentación de interfaz que ya usa internamente cada cuadrícula montada, de modo que una página sin ninguna cuadrícula - solo un botón, por ejemplo - puede reutilizar exactamente el mismo aspecto:
| Función | Descripción |
|---|---|
Xcrud.toast(message, type) | Muestra la misma notificación toast que mostraría una acción de Guardar/Eliminar o una llamada propia a ->toast() desde un hook. |
Xcrud.spinnerHtml(ui) | Devuelve el marcado del spinner del tema como una cadena HTML. ui toma por defecto el propio valor predeterminado de XcrudConfig::$ui ('tailwind') cuando se omite. |
Xcrud.setButtonLoading(btn, isLoading, loadingLabel, ui) | Alterna un botón entre su estado normal y su estado de carga (deshabilitado, spinner, cambio de etiqueta opcional) - el mismo tratamiento que usa cada botón de Guardar/Eliminar mientras una petición está en curso. |
<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>
Este es exactamente el patrón que usa pages/async-demo.php - una página sin ningún widget $xcrud, que carga Xcrud::uiAssets() y core/xcrud.js directamente para obtener estos globales.
Configuración del lado del servidor para uso entre orígenes
Cuando el frontend y el backend se sirven desde orígenes distintos, varios ajustes de XcrudConfig necesitan alejarse de sus valores predeterminados de mismo origen:
| Propiedad | Tipo | Descripción |
|---|---|---|
$allowedOrigins | array | La lista blanca de CORS - orígenes autorizados a llamar a ajax_crud.php entre dominios. Un origen de frontend ausente de esta lista es la causa más común de un "error de red" del lado del navegador, aunque el backend haya respondido correctamente. |
$crossOriginSessionCookie | bool | Cuando es true, cambia la cookie de sesión de inicio de sesión a SameSite=None; Secure para que sobreviva a una llamada fetch(..., {credentials: 'include'}) entre orígenes. Solo hace falta cuando $loginAuthentication también está activo y el frontend está en otro origen. Requiere un contexto genuinamente seguro (HTTPS real, o ambos lados en localhost/127.0.0.1). |
$forceApiUrl | string | Obliga a todos los widgets de todas las páginas a llamar a esta URL absoluta para la API, en lugar de la ruta relativa core/ajax_crud.php por defecto - necesario cuando el HTML se sirve desde un origen distinto al de la API. |
$forceUploadUrl | string | La misma idea para el endpoint de subida de archivos. |
$forceGalleryUrl | string | La misma idea para el endpoint de galería. |
$forceMediaUrl | string | La misma idea para images_handler.php, el endpoint firmado a través del cual se sirve realmente cada archivo subido. |
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';