Frontend and Backend Events
This page tells you how the browser and the server send events to each other.
The framework has three event systems. Each system has its own area.
| System | Where it runs | Use it to | Reference |
|---|---|---|---|
| PHP events | Server | Let plugins change the behavior of other plugins, of the theme, and of the DGS. | Events, DGS events, Theme package |
Jimbo events |
Browser | Let scripts react when jimbo.js or a template does something (opens a dialog, shows a form). |
Jimbo.js |
Response actions |
Server to browser | Tell the browser what to do after a request. | Response |
There is no permanent connection between the browser and the server. Each message from the server is the reply to an HTTP request.
The full loop
The parts:
- Browser to server. A script sends an HTTP request to a plugin method, or it fires a backend event of a DGS.
- Server. The plugin method does the work. PHP events let other plugins take part.
- Server to browser. The method sets an action in the
Response. - Browser.
Jimbo.response()does the action. Built-in actions change the page. A custom action calls your function.
Browser to server
Call a plugin method
Use an onJson method for a request from JavaScript.
/**
* @urlRule ~^/orders/([0-9]+)/done/$~
* @area backend
* @userType user
*/
public function onJsonDone(Response &$response, int $id): bool
{
$this->object->changeStatus($id, 'done');
$response->setAction(Response::ACTION_CALLBACK);
$response->name = 'Orders.onDone';
$response->idOrder = $id;
return true;
}
const Orders = {
done: function (id) {
Jimbo.loadJson('/orders/' + id + '/done/');
},
onDone: function (data) {
jQuery('#order-' + data.idOrder).addClass('m-done');
}
};
Jimbo.loadJson(url, callback) shows the loading indicator, sends a GET request, and gives the reply to Jimbo.response(). The optional callback also gets the data.
For a POST request, use jQuery and give the reply to Jimbo.response():
Jimbo.showLoading();
jQuery.post(url, {comment: text}, function (data) {
Jimbo.response(data);
}, 'json');
Jimbo.response() hides the loading indicator.
Submit a form
A form that submits into a hidden <iframe> needs an onAjax method. The HUI form and the HUI dialog make such a form. See Response.
Fire a backend event of a DGS
A page with a DGS list has a JavaScript object for the store. This object sends an event to the store on the server. You do not make a URL rule or a plugin method.
Frontend:
const store = Jimbo.getDataGridStoreInstance('orders');
store.fireBackendEvent(
'EVENT_ORDERS_RECALCULATE',
{idCustomer: 15},
function (response) {
// Optional. Runs after Jimbo.response(response).
},
function (xhr) {
// Optional. Runs if the HTTP request fails.
}
);
'orders' is the ident of the store. The list template makes the object with the URL of the list. On a page without the list, give the URL:
const store = Jimbo.getDataGridStoreInstance('orders', {baseUrl: '/orders/'});
The URL is for that store only. It does not change the URL of a different store.
Backend. Add a listener to the store before onRequest():
use core\store\event\FrontendStoreActionEvent;
public function onDisplayOrders(Response &$response): bool
{
$store = $this->createStoreInstance('orders');
$store->addEventListener(
'EVENT_ORDERS_RECALCULATE',
function (FrontendStoreActionEvent &$event) {
$data = $event->getData();
$this->object->recalculate($data['idCustomer']);
$response = &$event->getResponse();
$response->addNotification(__('The totals are correct now.'));
$response->setAction(Response::ACTION_RELOAD);
}
);
$store->onRequest($response);
return true;
}
What occurs:
- The request goes to the same URL as the list. Thus the same plugin method runs, with the same permission checks.
- The reply is JSON (
Response::JSON). The keydatacontains the data of the event. A listener can change them. - A listener sets an action in the same manner as a plugin method.
- If a listener throws an exception, the reply is an alert. See Frontend events in DGS.
A store class can also get all the events in one method. Implement IFrontendEventListener. See Frontend events in DGS.
The methods of FrontendStoreActionEvent:
| Method | Returns |
|---|---|
getType() |
The event name. |
getData() |
The data from the browser (by reference). |
getPrimaryKeyValue() |
The primary key value, if the request has it. |
getResponse() |
The Response (by reference). |
getActionInstance() |
The FrontendEventAction. |
Server to browser
The server tells the browser what to do with an action in the Response.
| You want to | Use |
|---|---|
| Show a message, reload, redirect, show form errors | A built-in action. See Actions. |
| Call one function of your script with data | Response::ACTION_CALLBACK |
| Add a behavior that many pages use | Your own action with Jimbo.set<Action>Response |
See Add your own action.
Events in the browser
jimbo.js has an event bus. A script listens with Jimbo.addListener() and fires with Jimbo.fireEvent().
Jimbo.addListener(Jimbo.EVENT_ON_DISPLAY_STORE_FORM, function (event, params) {
if (params.store === 'orders') {
Orders.initForm();
}
});
The most important events:
| Event | Fired when | Parameters |
|---|---|---|
Jimbo.EVENT_ON_INIT |
Jimbo.init() is complete. |
none |
Jimbo.EVENT_ON_DISPLAY_STORE_FORM |
A DGS form shows. | store (ident), mode |
Jimbo.EVENT_OPEN_DIALOG |
A DGS form or a HUI dialog opens. | none |
Jimbo.EVENT_BEFORE_CLOSE_DIALOG |
A DGS form starts to close. | event (the Bootstrap event) |
Jimbo.EVENT_BEFORE_LOAD_FORM |
jimbo.js starts to load a DGS form. |
The load options. A listener can change them. |
Jimbo.EVENT_CALL_ERROR_FIELD |
jimbo.js shows a field error. |
input, message, override |
Jimbo.EVENT_CALL_GROWL |
jimbo.js shows a notification. |
caption, description, persistent, stop |
Jimbo.EVENT_ON_DISPLAY_WIZARD_STEP |
A wizard step shows. | The wizard object. |
The full description of each event is in Jimbo.js.
Use these events to start the JavaScript of content that the page loads later. A DGS form is not in the page when the page loads. Thus jQuery(document).ready() is too early for its fields.
Your own browser events
A plugin can fire its own event. Other scripts can then listen.
// The plugin Orders tells other scripts that an order changed.
Jimbo.fireEvent('orders_changed', {idOrder: 15});
// A different plugin listens.
Jimbo.addListener('orders_changed', function (event, params) {
Dashboard.reloadTotals();
});
- Start the event name with the name of your plugin.
- Give the parameters as one object. The listener gets it as the second argument. An array is also one argument.
Events on the server
A request from the browser can cause PHP events. Use them when a plugin must react to the work of a different plugin.
| Area | Examples | Reference |
|---|---|---|
| Core | Core::EVENT_ON_REQUEST, Core::EVENT_ON_RESPONSE |
Events |
| DGS | Store::EVENT_BEFORE_INSERT, Store::EVENT_ON_FETCH_FORM |
DGS events |
| Theme | ITheme::EVENT_THEME_BEFORE_FETCH_MAIN, ITheme::EVENT_THEME_HEAD_BOTTOM |
Theme package |
Core::EVENT_ON_RESPONSE runs for each Response before the server sends it. The target of the event is the Response. A listener can add a parameter to each response:
$this->addEventListener(Core::EVENT_ON_RESPONSE, function (FestiEvent &$event) {
$response = &$event->getTarget();
if ($response->getType() == Response::JSON) {
$response->addParam('serverTime', time());
}
});
Rules
- Do not make JavaScript text on the server from user input. Send data, and let a function in a static file use the data.
- Use
onJsonfor requests from JavaScript andonAjaxfor forms that submit into the hidden<iframe>. - Give each reply to
Jimbo.response(). Then notifications, form errors, and redirects work in the same manner on each page. - Use a custom action or
ACTION_CALLBACK. Do not use the parameterjswhen the script needs data. - Start the names of your events and actions with the name of your plugin.