Drab - Access the browser User Interface from the Server Side. No Javascript programming needed anymore!
Drab extends Phoenix Framework to "remote control" UI on the browser, live. The idea is to move all User Interface logic to the server-side, to eliminate Javascript and Ajax calls.
- Client side:
<div class="progress">
<div class="progress-bar" role="progressbar" style="width:0%">
</div>
</div>
<button drab-click="perform_long_process">Click to start processing</button>
- Server side:
def perform_long_process(socket, dom_sender) do
steps = MyLongProcess.number_of_steps()
for i <- 1..steps do
MyLongProcess.perform_step(i)
# update the progress bar after each of MyLongProcess steps
socket
|> update(
css: "width",
set: "#{i * 100 / steps}%",
on: ".progress-bar")
|> update(
:html,
set: "#{Float.round(i * 100 / steps, 2)}%",
on: ".progress-bar")
end
socket |> insert(class: "progress-bar-success", into: ".progress-bar")
end
See Demo Page for live demo and description.
-
Erlang ~> 19
-
Elixir ~> 1.3
-
Phoenix ~> 1.2
So far the process of the installation is rather manually, in the future will be automatized.
- Add
drab
to your list of dependencies inmix.exs
in your Phoenix application and install it:
def deps do
[{:drab, "~> 0.3.1"}]
end
$ mix deps.get
$ mix compile
- Add
jquery
andboostrap
topackage.json
:
"dependencies": {
"jquery": ">= 3.1.1",
"bootstrap": "~3.3.7"
}
You may ommit this step if you are not planning to use DOM, jQuery, Drab.Query and Drab.Modal - see Domless Drab
- Add jQuery as a global at the end of
brunch-config.js
:
npm: {globals: {
$: 'jquery',
jQuery: 'jquery',
bootstrap: 'bootstrap'
}}
You may ommit this step if you are not planning to use DOM, jQuery, Drab.Query and Drab.Modal - see Domless Drab
- And install it:
$ npm install && node_modules/brunch/bin/brunch build
- Initialize Drab client library by adding to the layout page (
web/templates/layout/app.html.eex
)
<%= Drab.Client.js(@conn) %>
just after the following line:
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
- Initialize Drab sockets by adding the following to
web/channels/user_socket.ex
:
use Drab.Socket
Congratullations! You have installed Drab and you can proceed with your own Commanders.
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.
To enable Drab on the specific pages, you need to add the directive use Drab.Controller
to your application
controller.
Remember the difference: controller
renders the page while commander
works on the live page.
- Generate the page Commander. Commander name should correspond to controller, so PageController should have PageCommander:
$ mix drab.gen.commander Page
* creating web/commanders/page_commander.ex
Add the following line to your Example.PageController:
use Drab.Controller
- As described in the previous task, add
Drab.Controller
to your page Controller (eg.web/controllers/page_controller.ex
in the default app):
defmodule DrabExample.PageController do
use Example.Web, :controller
use Drab.Controller
def index(conn, _params) do
render conn, "index.html"
end
end
- Edit the commander file
web/commanders/page_commander.ex
and add some real action - theonload
callback which fires when the browser connects to Drab.
defmodule DrabExample.PageCommander do
use Drab.Commander
onload :page_loaded
# Drab Callbacks
def page_loaded(socket) do
socket
|> update(:html, set: "Welcome to Phoenix+Drab!", on: "div.jumbotron h2")
|> update(:html,
set: "Please visit <a href='https://tg.pl/drab'>Drab</a> page for more examples and description",
on: "div.jumbotron p.lead")
end
end
Function update/3
(shorthand for Drab.Query.update/3
) with :html
parameter sets the HTML of DOM object,
analogically to $().html()
on the client side.
Finally! Run the phoenix server and enjoy working on the Dark Side of the web.
All above is available for download here
- Client-side: assign the events directly in HTML, using
drab-event=event_name
anddrab-handler='event_handler'
combination of attributes, whenevent_name
is the JS event name andevent_handler
is the function name in the Commander. This function will be fired on event. There is also a shorthand for this:drab-[event_name]=event_handler
(currently: click, change, keyup, keydown are defined). Example:
<button drab-click='button_clicked'>Clickme!</button>
- Server-side: when clicked, this button will launch the following action on the corresponding commander:
defmodule Example.PageCommander do
use Drab.Commander
# Drab Events
def button_clicked(socket, dom_sender) do
socket
|> update(:text, set: "alread clicked", on: this(dom_sender))
end
end
As you probably guess, this changes button description (Drab.Query.update/3
used with :text
).
Visit Demo Page for a live demo and more description.
Visit Docs with Examples - documentation with short examples.
(c)2016 Tomek "Grych" Gryszkiewicz, grych@tg.pl