Those use cases show what is up to the application developer responsibility (on diagrams, it is the controller actor), what is done automatically by the framework (light blue rectangle).

Displaying a form and saving an object

Two actions are involved, using 2 services:

Diagram
Figure 1. Sequence Diagram Rendering Form and Process Object
Code Sample: Form + Save Workflow
    def userForm(User user) {                           (1)
        user ?= new User()                              (2)

        UiFormSpecifier f = new UiFormSpecifier()       (3)
        f.ui user, {
            hiddenField user.subsidiary_
            hiddenField user.origin_
            section "User", {
                field user.username_
                field user.firstName_
                field user.lastName_
                ajaxField user.manager_, this.&selectUserM2O as MC
                field user.trigram_
                field user.password_
            }
            section "Coords", {
                field user.businessUnit_
                field user.job_
                field user.directPhone_
                field user.additionalPhone_
                field user.mail_
                field user.mainSubsidiary_
                field user.allowedSubsidiaries_
            }
            // [. . .]
            formAction this.&saveUser as MC, user.id    (4)
        }

        taackUiService.show new UiBlockSpecifier().ui { (5)
            modal {
                form "User Form", f, BlockSpec.Width.MAX
            }
        }
    }

    @Transactional
    @Secured("ROLE_ADMIN")                              (6)
    def saveUser() {                                    (7)
        taackSaveService.saveThenRedirectOrRenderErrors(User, this.&listUser) (8)
    }
  1. Action displaying the form

  2. Create the object if object is null

  3. Create the form

  4. Form button that send the form data to the saveUser action

  5. show the form

  6. Secure the save action

  7. Action that will save the object

  8. Call to taackSaveService, here if the object is valid, user is redirected to listUsers action.

Display a table with sortable columns, inline actions, and a filter

Only one action is necessary to manage pagination, filtering and sorting:

Diagram
Figure 2. Sequence Diagram Managing Action on a Table to process a list of objects
Code Sample Filter and table
    def index() {                                                   (1)
        User cu = authenticatedUser as User

        UiFilterSpecifier f = buildUserTableFilter cu               (2)
        UiTableSpecifier t = buildUserTable f                       (3)

        UiBlockSpecifier b = new UiBlockSpecifier()                 (4)
        b.ui {
            tableFilter "Filter", f, "Users", t, BlockSpec.Width.MAX, {
                action ActionIcon.CREATE, this.&userForm as MC      (5)
            }
        }

        taackUiService.show(b, buildMenu())                         (6)
    }
  1. Action that display a list of objects

  2. Build the filter, here the filter takes the current connected user as parameter, because we want to be able to list user team.

  3. Build the table

  4. Build the block containing the table and the filter

  5. Add an action to create a new user

  6. Show the block

Warning
We exceptionally pass the filter to the buildTable for building the query and avoiding filter hacking

Display a modal then close it and refresh part of current content

Diagram
Figure 3. Sequence Diagram Managing Action on a Table to process a list of objects
Code Sample to close modal and refresh current page
taackSaveService.saveThenDisplayBlockOrRenderErrors(EngineeringChangeRequest,   (1)
new UiBlockSpecifier().ui {                                                     (2)
    closeModalAndUpdateBlock {                                                  (3)
        show "Projects", buildShowProjects(ecr), BlockSpec.Width.MAX, {
            action
                ActionIcon.ADD,
                Ecr2Controller.&projectsForm as MC,
                [id: ecr.id, ajaxBlockId: ajaxBlockId]
        }
    }
})
  1. After an action implying to save an object is called into a modal, you can close the modal and refresh page elements in one action

  2. saveThenDisplayBlockOrRenderErrors take a UiBlockSpecifier as parameter

  3. closeModalAndUpdateBlock will first close the last opened modal and then apply the modification

  4. Here, the block with the name contained in ajaxBlockId will be updated

TODO

  • Updating a portion of a page

  • Show some object with an editable field

  • Show a graph

  • Export a table in CSV

  • Rendering a block in a PDF

  • Rendering a block in a Mail

  • …​