Actions
The humhub.modules.action
module provides a mechanism for binding Javascript action handlers to dom events as the click of a button.
The following example binds the action example.myAction
to click
events of a button.
The action handler uses the client
module for calling an url defined by data-action-url
.
View:
<button data-action-click="example.myAction" data-action-url="<?= $myActionUrl ?>">Call my action!</button>
Module:
var myAction = function(evt) {
client.get(evt).then(function(response) {
//evt.$trigger is the button itself in form of a jQuery instance
evt.$trigger.text(response.output);
module.log.success('Done!');
}).catch(function(e) {
module.log.error(e, true);
});
}
module.export({
myAction: myAction
});
Note: Don't forget to export your action handler, otherwise it won't be accessible.
Action Handlers
There are different types of action handlers:
- Direct action handlers are directly passed to the
bindAction
function (see section Action Binding Mechanism).
View:
<div id="#myContainer">
<!-- Note, you won't have to define the name of your handler in this case -->
<button class="sendButton" data-action-url="<?= Url::to(...) ?>">Send</button>
</div>
Module:
// Bind a click handler to all .sendButton nodes within #myContainer
require('action').bindAction('#myContainer', 'click', '.sendButton', function(evt) {
client.post(evt).then(function(resp) {...});
});
- Registered action handlers are globaly registered by means of the
registerHandler
function and can be shared by modules.
View:
<button data-action-click="myRegisteredHandler">Magic!</button>
Module:
require('action').registerHandler('myRegisteredHandler', function(evt) {/*...*/});
- Component action handlers are used to execute actions of a ui Components
- Namespace action handlers will be searched within the humhub namespace if there is no other matching handler
<!-- A click to this button will execute the exported myFunction of myModule -->
<button data-action-click="myModule.myFunction">Do something !</button>
Note: Component and Namespace action handlers are the most common and prefered handler types.
TIP: You can define multiple actions with different urls on the same $trigger by means of for example
data-action-click-url
anddata-action-change-url
.
Action Event
All action handler functions are provided with an action event which is a derivate of $.Event
and provides, beside others, the following attributes:
$trigger
: The jquery instance, which was responsible for triggering the event e.g. a button.$target
: Can be used to define a target component or widget and is defined by thedata-action-target
attribute of $trigger. If not explicitly set, the $trigger node will also be the events $target. See the component section for more details.url
: Contains thedata-action-url
ordata-action-click-url
(will be prefered in case of click events).params
: Can be used to add additional action parameters by settingdata-action-params
or the more specificdata-action-click-params
in case of a click event.
View:
<button data-action-click="example.someAction" data-action-params='{"type":"example"}'>Call Action!</button>
Module:
var someAction = function(evt) {
alert(evt.params.type);
}
$form
: In case your $trigger is oftype="submit"
or has adata-action-submit
attribute, the action event will include a jquery instance of the sorrounding form or the form set by the $target.
View:
<?php $form = ActiveForm::begin(); ?>
<!-- ... Form Inputs ... -->
<button type="submit" data-action-click="example.submit" data-action-url="<?= $url ?>">Submit</button>
<?php ActiveForm::end(); ?>
Module:
var submit = function(evt) {
client.submit(evt).then(...).catch(...);
}
Info: The
client
module knows how to handle action events and will try to determine the url from the given event instance if no url was explicitly provided as argument. In case ofclient.submit
, the client will try to determine the url of the formsaction
if the trigger does not specify an action url.
originalEvent
: The original event which triggered the actionfinish
: This function is called to mark the action as completed, this function may be called manually to release the action block or remove the loader animation of a trigger withdata-ui-loader
flag. See the Action Blocking section for more information.
Action Blocking
To prevent actions from beeing executed multiple times before finishing, actions are blocked during the execution time by default. The blocking logic can be configured by setting the data-action-block
on the trigger node. The following block values are available:
- none: No blocking at all
- sync: Synchronous blocking, the block will be released after the handler finished. This is the default block for all non async trigger elements.
- async: The block has to be released manually by calling the
event.finish()
function. Note this block type is used by default for action handlers with a givendata-action-url
,data-action-submit
ortype="submit"
trigger.
Note:
client
calls asclient.get(evt)
orclient.submit(evt)
will call the eventsfinish
function automatically after receiving the server response, so you won't have to call it in your handler.
Action Binding Mechanism
The humhub.modules.action.bindAction
function is used to bind event types to all nodes of a given selector.
The following action bindings are available by default:
this.bindAction(document, 'click', '[data-action-click]');
this.bindAction(document, 'dblclick', '[data-action-dblclick]');
this.bindAction(document, 'change', '[data-action-change]');
Currently only click
, dbclick
, change
events are supported by default. This may change in the future.
You can extend the supported event types on demand as in the following example:
require('action').bindAction(document, 'customevent', '[data-action-customevent]');
NOTE: The first argument of the bindAction should be the first static (never removed from dom or lazy loaded) parent node of all nodes you wish to bind.
NOTE: Too many delegated events to the
document
is a performance antipattern.
How does it work:
In the previous example the bindAction call will bind a delegate to the document
:
$(document).on('customevent', '[data-action-customevent]', function() {...});
If the delegate handler receives an unhandled action event, it will rebind all bindings directly to the trigger elements and run the action. All upcoming events will directly be handled by the trigger, which prevents the bubbling latency.
NOTE: As long as you don't need any custom bindings, you won't have to worry about the binding mechanism.
TIP: Since humhub action binding is based on jquerys event delegation, you can use all event types of jquery.