drab v0.6.3 Drab.Commander
Drab Commander is a module to keep event handlers.
All the Drab functions (callbacks, event handlers) are placed in the module called Commander
. Think about
it as a controller for the live pages. Commanders should be placed in web/commanders
directory. Commander must
have a corresponding controller.
defmodule DrabExample.PageCommander do
use Drab.Commander
def click_button_handler(socket, dom_sender) do
...
end
end
Remember the difference: controller
renders the page while commander
works on the live page.
Event handler functions
Event handler is the function which process the request coming from the browser. It is done by running JS method
Drab.exec_elixir()
or from the DOM object with drab-handler
attribute. See Drab.Core
for description.
The event handler function receives two parameters:
socket
- the websocket used to communicate back to the pageargument
- an argument used in JS Drab.exec_elixir() method; when lauching an event viadrab-handler=function
atrribute, it is a map describing the sender object
All public functions with arity of 2 in the commander module must be considered as handlers
Please keep in mind that all public functions with arity of 2 in the commander may be called remotely from the browser.
Shared commanders
By default, only the page rendered with the corresponding controller may run handler functions in the
commander. But there is a possibility to create a shared commander, which is allowed to run from any page.
For this, you must mark the specific handlers as public, using public/1
macro. Please notice it is your
responsibility to make such functions safe.
If you want to restrict shared controller for only specified controller, you must use before_handler/1
callback with controller/1
and action/1
functions to check out where the function is calling from.
Callbacks
Callbacks are an automatic events which are launched by the system. They are defined by the macro in the Commander module:
defmodule DrabExample.PageCommander do
use Drab.Commander
onload :page_loaded
onconnect :connected
ondisconnect :dosconnected
before_handler :check_status
after_handler :clean_up, only: [:perform_long_process]
def page_loaded(socket) do
...
end
def connected(socket) do
...
end
def connected(store, session) do
# notice that this callback receives store and session, not socket
# this is because socket is not available anymore (Channel is closed)
...
end
def check_status(socket, sender) do
# return false or nil to prevent event handler to be launched
end
def clean_up(socket, dom_sender, handler_return_value) do
# this callback gets return value of the corresponding event handler
end
end
onconnect
Launched every time client browser connects to the server, including reconnects after server crash, network broken etc
onload
Launched only once after page loaded and connects to the server - exactly the same like onconnect
,
but launches only once, not after every reconnect
ondisconnect
Launched every time client browser disconnects from the server, it may be a network disconnect, closing the browser, navigate back. Disconnect callback receives Drab Store as an argument
before_handler
Runs before the event handler. If any of before callbacks return false
or nil
, corresponding event
will not be launched. If there are more callbacks for specified event handler function, all are processed
in order or appearance, then system checks if any of them returned false.
Can be filtered by :only
or :except
options:
before_handler :check_status, except: [:set_status]
before_handler :check_status, only: [:update_db]
after_handler
Runs after the event handler. Gets return value of the event handler function as a third argument.
Can be filtered by :only
or :except
options, analogically to before_handler
Using callbacks to check user permissions
Callbacks are handy for security. You may retrieve controller name and action name from the socket with
controller/1
and action/1
.
before_handler :check_permissions
def check_permissions(socket, _sender) do
if controller(socket) == MyApp.MyController && action(socket) == :index do
true
else
false
end
end
Broadcasting options
All Drab function may be broadcaster. By default, broadcasts are sent to browsers sharing the same page
(the same url), but it could be override by broadcasting/1
macro.
Modules
Drab is modular. You my choose which modules to use in the specific Commander by using :module
option
in use Drab.Commander
directive.
There is one required module, which is loaded always and can’t be disabled: Drab.Code
. By default, modules
Drab.Live
and Drab.Element
are loaded. The following code:
use Drab.Commander, modules: [Drab.Query]
will override default modules, so only Drab.Core
and Drab.Query
will be available.
Every module has its corresponding JS template, which is loaded only when module is enabled.
Using templates
Drab injects function render_to_string/2
into your Commander. It is a shorthand for
Phoenix.View.render_to_string/3
- Drab automatically chooses the current View.
Examples:
buttons = render_to_string("waiter_example.html", [])
Generate the Commander
There is a mix task (Mix.Tasks.Drab.Gen.Commander
) to generate skeleton of commander:
mix drab.gen.commander Name
See also Drab.Controller
Link to this section Summary
Functions
Drab may allow an access to specified Plug Session values. For this, you must whitelist the keys of the
session map. Only this keys will be available to Drab.Core.get_session/2
Retrieves action name in the controller, which rendered the page where handler is called from
Sets up the callback for after_handler. Receives handler function name as an atom and options
Sets up the callback for before_handler. Receives handler function name as an atom and options
Set up broadcasting listen subject for the current commander
Retrieves controller module, which generated the page the handler function is calling from, from the socket
Sets up the callback for onconnect. Receives handler function name as an atom
Sets up the callback for ondisconnect. Receives handler function name as an atom
Sets up the callback for onload. Receives handler function name as an atom
Make handler function public, so it can be called from any page
Link to this section Functions
Drab may allow an access to specified Plug Session values. For this, you must whitelist the keys of the
session map. Only this keys will be available to Drab.Core.get_session/2
defmodule MyApp.MyCommander do
user Drab.Commander
access_session [:user_id, :counter]
end
Keys are whitelisted due to security reasons. Session token is stored on the client-side and it is signed, but not encrypted.
Retrieves action name in the controller, which rendered the page where handler is called from.
Sets up the callback for after_handler. Receives handler function name as an atom and options.
after_handler :event_handler_function
See Drab.Commander
summary for details.
Sets up the callback for before_handler. Receives handler function name as an atom and options.
before_handler :event_handler_function
See Drab.Commander
summary for details.
Set up broadcasting listen subject for the current commander.
It is used by broadcasting functions, like Drab.Element.broadcast_prop/3
or Drab.Query.insert!/2
.
When the browser connects to Drab page, it gets the broadcasting subject from the commander. Then,
it will receive all the broadcasts coming to this subject.
Default is :same_path
Options:
:same_path
(default) - broadcasts will go to the browsers rendering the same url:same_controller
- broadcasted message will be received by all browsers, which renders the page generated by the same controller"topic"
- any topic you want to set, messages will go to the clients sharing this topic
See Drab.Core.broadcast_js/2
for more.
Retrieves controller module, which generated the page the handler function is calling from, from the socket.
Sets up the callback for onconnect. Receives handler function name as an atom.
onconnect :event_handler_function
See Drab.Commander
summary for details.
Sets up the callback for ondisconnect. Receives handler function name as an atom.
ondisconnect :event_handler_function
See Drab.Commander
summary for details.
Sets up the callback for onload. Receives handler function name as an atom.
onload :event_handler_function
See Drab.Commander
summary for details.
Make handler function public, so it can be called from any page.
This allow you to create a shared commanders
defmodule MyApp.MyCommander
use Drab.Commander
public [:handler1, :handler2]
def handler1(socket, sender) do
...
end
end
Without marking as public
, function may only be called from the page rendered with the corresponding controller.
When whitelisted, functions may be called from any page using the dot syntax:
<button drab-click="MyApp.MyCommander.handler1">handler 1</button>
or from JS:
Drab.exec_elixir("MyApp.MyCommander.handler1", {click: "clickety-click"});
Running non-public functions with dot syntax raises the exception on Phoenix side.