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:

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

        UiFormSpecifier f = new UiFormSpecifier() (3)
        f.ui user, {
            hiddenField user.subsidiary_
            hiddenField user.origin_
            section "User", {
                field "Username", user.username_
                field "First Name", user.firstName_
                field "Last Name", user.lastName_
                ajaxField "Manager", user.manager_, this.&selectUserM2O as MC
                field "Trigram", user.trigram_
                field "Passwd", user.password_
            section "Coords", {
                field "Business Unit", user.businessUnit_
                field "Job", user.job_
                field "Tel.", user.directPhone_
                field "Other Tel.", user.additionalPhone_
                field "Mail", user.mail_
                field "Subsidiary", user.mainSubsidiary_
                field "Allowed Subsidiaries", user.allowedSubsidiaries_
            // [. . .]
            formAction "Save", this.&saveUser as MC,, true (4)

        UiBlockSpecifier b = new UiBlockSpecifier()
        b.ui {
            modal {
                ajaxBlock "userForm", {
                    form "User Form", f, BlockSpec.Width.MAX
        } (5)

    @Secured("ROLE_ADMIN") (6)
    def saveUser(String redirectAction) { (7)
        taackSimpleSaveService.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 taackSimpleSaveService, 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:

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 {
            ajaxBlock "userList", {
                tableFilter "Filter", f, "Users", t, BlockSpec.Width.MAX, {
                    if (cu.authorities*.authority.contains("ROLE_ADMIN"))
                        action "Create User",
                               ActionIcon.CREATE, this.&userForm as MC, true (5)
        }, 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

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

Figure 3. Sequence Diagram Managing Action on a Table to process a list of objects
Code Sample to close modal and refresh current page
        taackSimpleSaveService.saveThenDisplayBlockOrRenderErrors(EngineeringChangeRequest, (1)
        new UiBlockSpecifier().ui { (2)
            closeModalAndUpdateBlock { (3)
                ajaxBlock ajaxBlockId, { (4)
                    show "Projects", buildShowProjects(ecr), BlockSpec.Width.MAX, {
                        action "Edit projects 2", ActionIcon.ADD,
                            Ecr2Controller.&projectsForm as MC,
                            [id:, ajaxBlockId: ajaxBlockId], true
  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


  • 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

  • …​