Actions

Actions is the core component allowing interactivity in Reblocks applications.

Actions are callbacks that are stored in a session and can be called from the browser using AJAX, POST or GET requests.

There are two types of actions:

Application actions

This kind of actions is good when you want to build a scalable application, because amount of memory they are taking does not grow with number of user sessions.

Application action should be a function which only depends on it's argument. They should not closeup any variables because the same function will be called for every application's user.

Here is an example, how to define such action which will create a new user:

(reblocks/app:defapp demo-actions
  :autostart nil)

(reblocks/app-actions:define-action create-user demo-actions (name email)
  (format t "User ~A with email ~A was created.~%"
          name email))

After that, this function can be called by name

(let ((app (make-instance 'demo-actions)))
  (reblocks/actions:eval-action app
                                "create-user"
                                (list "Bob"
                                      "bob@40ants.com"))))
=> "User Bob with email bob@40ants.com was created."

Session actions

Session actions can be a stand-alone functions or closures. This makes it easier to catch some variables and to use them when user interacts with application.

However, such closures are stored in a hash table bound to the each session. This makes a few consequences:

In the next example, we can see how it is easy to catch USER variable into the action's closure and then use it when email will be provided:

(let ((user "Bob"))
  (reblocks-tests/utils:with-test-session ()
    (let ((action-id
            (reblocks/actions:make-action
             (lambda (email)
               (format t "Changing email for user ~A to ~A"
                       user email)))))
      (reblocks/actions:eval-action nil
                                    action-id
                                    (list "bob@40ants.com")))))
.. <DEBUG> [12:11:44] reblocks/actions actions.lisp (eval-action) -
..   Calling REBLOCKS/ACTIONS::ACTION: #<FUNCTION (LAMBDA
..                                                    (
..                                                     EMAIL)) {7009B6328B}>
..   with REBLOCKS/ACTIONS::ARGUMENTS: ("bob@40ants.com")
..   and REBLOCKS/ACTIONS::ACTION-NAME: "11626:ca7db51f4b0ffb082dcc560eed1b6121707d9677"
..   
.. Changing email for user Bob to bob@40ants.com
=> NIL

With application-wide action you'll have to render user's id in the hidden field of HTML form and then to retrieve the user object from the database when action get called.

Now lets see how to use actions from the frontend!

Using at the Frontend

At the fronted you might want to call actions as the result of user's click, form submit or some other act, for example, by timer.

Reblocks provides a thin JS layer which includes following functions:

initiateAction(actionCode, options)

This function calls given action using AJAX. You have to pass optional arguments as JS object options:

{
    "method": "POST",
    "args": {},
    "url": undefined,
    "on_success": undefined,
    "on_failure": undefined,
}

Here is an example which uses make-action and renders usual HTML link as a button bound to an anonymous lisp function:

Also, you might generate a link using make-action-url function and use it as HREF argument of any link on a page. Click on such link will trigger the action.

Here I intentionally didn't add a "button" class to show that this is just a link.

Pay attention how this example flickers when you click the link. This is because the whole iframe's content is reloaded when you click the link. In the previous example this is not happening because click leads to an AJAX requst and only a piece of page get updated.

In the next example, we'll pass arguments to our action. To do this, we have to call make-action and render JS code manually:

initiateFormAction(actionCode, form, options)

This version of function accepts a form jquery object as the second argument. Options argument has the same meaning as for initiateAction function, but args attrbute is formed from the serialized form fields and default method is taken from the form's method attribute.

Next example shows how to process a form submit, using a callback, registered with make-js-form-action: