drab v0.4.0 Drab.Query

Drab module which provides interface to DOM objects on the server side. You may query (select/2) or manipulate (update/2, insert/2, delete/2, execute/2) the selected DOM object.

General syntax:

return = socket |> select(what, from: selector)
socket |> update(what, set: new_value, on: selector)
socket |> insert(what, into: selector)
socket |> delete(what, from: selector)
socket |> execute(what, on: selector)

where:

  • socket - websocket used in connection
  • selector - string with a DOM selector
  • what - a representation of jQuery method; an atom (eg. :html, :val) or key/value pair (like attr: name). An atom will launch the corresponding jQuey function without any arguments (eg. .html()). Key/value pair will launch the method named as the key with arguments taken from its value, so text: "some" becomes .text("some").

Object manipulation (update/2, insert/2, delete/2, execute/2) functions return socket. Query select/2 returns either a found value (when using singular version of jQuery method, eg :html), or a Map of %{name|id|__undefined_XX => value}, when using plural - like :htmls.

Select queries always refers to the page on which the event were launched. Data manipulation queries (update/2, insert/2, delete/2, execute/2) changes DOM objects on this page as well, but they have a broadcast versions: update!/2, insert!/2, delete!/2 and execute!/2, which works the same, but changes DOM on every currently connected browsers, which has opened the same URL, same controller, or having the same channel topic (see Drab.Commander.broadcasting/1 to find out more).

Events

Events are defined directly in the HTML by adding drab-event and drab-handler properties:

<button drab-event='click' drab-handler='button_clicked'>clickme</button>

Clicking such button launches DrabExample.PageCommander.button_clicked/2 on the Phoenix server.

There are few shortcuts for the most popular events: click, keyup, keydown, change. For this event an attribute drab-EVENT_NAME must be set. The following like is an equivalent for the previous one:

<button drab-click='button_clicked'>clickme</button>

Normally Drab operates on the user interface of the browser which generared the event, but it is possible to broadcast the change to all the browsers which are currently viewing the same page. See the bang functions in Drab.Query module.

Event handler functions

The event handler function receives two parameters:

  • socket - the websocket used to communicate back to the page by Drab.Query functions
  • dom_sender - a map contains information of the object which sent the event; keys are binary strings

The dom_sender map:

%{
  "id"      => "sender object ID attribute",
  "name"    => "sender object 'name' attribute",
  "class"   => "sender object 'class' attribute",
  "text"    => "sender node 'text'",
  "html"    => "sender node 'html', result of running .html() on the node",
  "val"     => "sender object value",
  "data"    => "a map with sender object 'data-xxxx' attributes, where 'xxxx' are the keys",
  "event"   => "a map with choosen properties of `event` object"
  "drab_id" => "internal"
}

Example:

def button_clicked(socket, dom_sender) do
  socket |> update(:text, set: "clicked", on: this(dom_sender))
end

Summary

Functions

Removes nodes, classes or attributes from selected node

Like Dom.Query.delete/2, but broadcasts to all currently connected browsers

Execute given jQuery method on selector. To be used in case built-in method calls are not enough

Like Drab.Query.execute/2, but broadcasts to all currently connected browsers, which have the same URL opened

Adds new node (html) or class to the selected object

Like Drab.Query.insert/2, but broadcast to all currently connected browsers

Returns a value get by executing jQuery method on selected DOM object, or a Map of %{name|id|_undefined[INCREMENT]: value} when method name is plural, or a Map of %{ method => returns_of_methods}, when the method is :all

Finds the DOM object which triggered the event. To be used only in event handlers

Like Drab.Query.this/1, but returns CSS ID of the object, so it may be used with broadcasting functions

Updates the DOM object corresponding to the jQuery method

Like Drab.Query.update/2, but broadcasts to all currently connected browsers

Functions

delete(socket, options)

Removes nodes, classes or attributes from selected node.

With selector and no options, removes it and all its children. With given from: selector option, removes only the content, but element remains in the DOM tree. With options class: class, from: selector removes class from given node(s). Given option prop: property or attr: attribute it is able to remove property or attribute from the DOM node.

Waits for the browser to finish the changes and returns socket so it can be stacked.

Options:

  • class: class - class name to be deleted
  • prop: property - property to be removed from selected node(s)
  • attr: attribute - attribute to be deleted from selected node(s)
  • from: selector - DOM selector

Example:

socket |> delete(".btn")       # remove all `.btn`
socket |> delete(from: "code") # empty all `<code>`, but node remains
socket |> delete(class: "btn-success", from: "#button")
delete!(socket, options)

Like Dom.Query.delete/2, but broadcasts to all currently connected browsers.

Broadcast functions are asynchronous, do not wait for the reply from browsers, immediately return :sent.

execute(socket, options)

Execute given jQuery method on selector. To be used in case built-in method calls are not enough.

Waits for the browser to finish the changes and returns socket so it can be stacked.

socket |> execute(:click, on: "#mybutton")
socket |> execute(trigger: "click", on: "#mybutton")
socket |> execute("trigger("click")", on: "#mybutton")
execute(socket, method, options)

See Drab.Query.execute/2

execute!(socket, options)

Like Drab.Query.execute/2, but broadcasts to all currently connected browsers, which have the same URL opened.

Broadcast functions are asynchronous, do not wait for the reply from browsers, immediately return :sent.

execute!(socket, method, options)

See Drab.Query.execute!/2

insert(socket, options)

Adds new node (html) or class to the selected object.

Waits for the browser to finish the changes and returns socket so it can be stacked.

Options:

  • class: class - class name to be inserted
  • into: selector - class will be added to specified selectors; only applies with :class
  • before: selector - creates html before the selector
  • after: selector - creates html node after the selector
  • append: selector - adds html to the end of the selector (inside the selector)
  • prepend: selector - adds html to the beginning of the selector (inside the selector)

Example:

socket |> insert(class: "btn-success", into: "#button")
socket |> insert("<b>warning</b>", before: "#pane")
insert(socket, html, options)

See Drab.Query.insert/2

insert!(socket, options)

Like Drab.Query.insert/2, but broadcast to all currently connected browsers.

Broadcast functions are asynchronous, do not wait for the reply from browsers, immediately return socket.

insert!(socket, html, options)

See Drab.Query.insert/2

select(socket, options)

Returns a value get by executing jQuery method on selected DOM object, or a Map of %{name|id|_undefined[INCREMENT]: value} when method name is plural, or a Map of %{ method => returns_of_methods}, when the method is :all.

Plural version uses name attribute as a key, or id, when there is no name, or __undefined_[INCREMENT], when neither id or name are specified.

In case the method requires an argument (like attr()), it should be given as key/value pair: method_name: “argument”.

Options:

  • from: “selector” - DOM selector which is queried
  • attr: “attribute” - DOM attribute
  • prop: “property” - DOM property
  • css: “css”
  • data: “att” - returns the value of jQuery data("attr") method

Examples:

name = socket |> select(:val, from: "#name")
# "Stefan"
name = socket |> select(:vals, from: "#name")
# %{"name" => "Stefan"}
font = socket |> select(css: "font", from: "#name")
# "normal normal normal normal 14px / 20px \"Helvetica Neue\", Helvetica, Arial, sans-serif"
button_ids = socket |> select(datas: "button_id", from: "button")
# %{"button1" => 1, "button2" => 2}

Available jQuery methods:

html text val 
width height 
innerWidth innerHeight outerWidth outerHeight 
position offset scrollLeft scrollTop
attr: val prop: val css: val data: val

Available jQuery plural methods:

htmls texts vals 
widths heights
innerWidths innerHeights outerWidths outerHeights 
positions offsets scrollLefts scrollTops
attrs: val props: val csses: val datas: val

:all

In case when method is :all, executes all known methods on the given selector. Returns Map %{name|id => medthod_return_value}. The Map key are generated in the same way as those with plural methods.

socket |> select(:all, from: "span")
%{"first_span" => %{"height" => 16, "html" => "First span with class qs_2", "innerHeight" => 20, ...

Additionally, id and name attributes are included into a Map.

select(socket, method, options)

See Drab.Query.select/2

this(dom_sender)

Finds the DOM object which triggered the event. To be used only in event handlers.

def button_clicked(socket, dom_sender) do
  socket |> update(:text, set: "alread clicked", on: this(dom_sender))
  socket |> update(attr: "disabled", set: true, on: this(dom_sender))
end        

Do not use it with with broadcast functions (Drab.Query.update!, Drab.Query.insert, Drab.Query.delete, Drab.Query.execute!), because it returns the exact DOM object. In case if you want to broadcast, use Drab.Query.this!/1 instead.

this!(dom_sender)

Like Drab.Query.this/1, but returns CSS ID of the object, so it may be used with broadcasting functions.

def button_clicked(socket, dom_sender) do
  socket |> update!(:text, set: "alread clicked", on: this!(dom_sender))
  socket |> update!(attr: "disabled", set: true, on: this!(dom_sender))
end

Raises exception when being used on the object without an ID.

update(socket, options)

Updates the DOM object corresponding to the jQuery method.

In case when the method requires an argument (like attr()), it should be given as key/value pair: method_name: “argument”.

Waits for the browser to finish the changes, returns socket so it can be stacked.

Options:

  • on: selector - DOM selector, on which the changes are made
  • set: value - new value
  • attr: attribute - DOM attribute
  • prop: property - DOM property
  • class: class - class name to be replaced by another class
  • css: updates a given css
  • data: sets the jQuery data storage by calling data("key", value); it does not update the data-* attribute

Examples:

socket |> update(:text, set: "saved...", on: "#save_button")
socket |> update(attr: "style", set: "width: 100%", on: ".progress-bar")
# the same effect:
socket |> update(css: "width", set: "100%", on: ".progress-bar")

Update can also switch the classes in DOM object (remove one and insert another):

socket |> update(class: "btn-success", set: "btn-danger", on: "#save_button")

You can also cycle between values - switch to the next value from the list or to the first element, if the actual value is not on the list:

socket |> update(:text, set: ["One", "Two", "Three"], on: "#thebutton")
socket |> update(css: "font-size", set: ["8px", "10px", "12px"], on: "#btn")

When cycling through the class attribute, system will update the class if it is one in the list. In the other case, it will add the first from the list.

socket |> update(:class, set: ["btn-success", "btn-danger"], on: "#btn")

Please notice that cycling is only possible on selectors which returns one node.

Another possibility is to toggle (add if not exists, remove in the other case) the class:

socket |> update(:class, toggle: "btn-success", on: "#btn")

Available jQuery methods: see Drab.Query.select/2

update(socket, method, options)

See Drab.Query.update/2

update!(socket, options)

Like Drab.Query.update/2, but broadcasts to all currently connected browsers.

Broadcast functions are asynchronous, do not wait for the reply from browsers, immediately return socket.

update!(socket, method, options)

See Drab.Query.update!/2