以下用例展示了哪些工作由应用开发者负责(在图中表示为 controller 角色),哪些工作由框架自动完成(浅蓝色矩形框)。

显示表单并保存对象

此流程涉及两个动作(action)和 2 个服务:

Diagram
Figure 1. 渲染表单与处理对象的时序图
代码示例:表单 + 保存工作流
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 显示表单的动作
2 若对象为 null 则新建对象实例
3 创建表单定义器
4 表单提交按钮,将表单数据发送到 saveUser 动作
5 显示表单
6 为保存动作添加权限保护
7 保存对象的动作
8 调用 taackSaveService,如果对象校验通过,用户将被重定向到 listUsers 动作。

显示支持列排序、行内操作及筛选器的表格

只需一个动作即可统一处理分页、筛选和排序:

Diagram
Figure 2. 在表格上管理动作以处理对象列表的时序图
筛选器与表格代码示例
def index() {                                                   (1)
    User cu = authenticatedUser as User

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

    UiBlockSpecifier b = new UiBlockSpecifier().ui {            (4)
        tableFilter(f, t) {
            menuIcon ActionIcon.ADD, this.&userForm as MC       (5)
        }
    }

    taackUiService.show(b, buildMenu())                         (6)
}
1 显示对象列表的动作
2 构建筛选器,此处筛选器接收当前登录用户作为参数,以便列出该用户所属团队
3 构建表格
4 构建包含表格和筛选器的块(Block)
5 添加创建新用户的操作图标
6 显示该块
此处我们特地将筛选器传递给 buildTable 以构建查询,从而防止 筛选器篡改(filter hacking)。

显示模态窗口,随后关闭它并刷新当前页面的部分内容

Diagram
Figure 3. 在表格上管理动作以处理对象列表的时序图
关闭模态窗口并刷新当前页面的代码示例
taackSaveService.saveThenDisplayBlockOrRenderErrors(EngineeringChangeRequest,   (1)
    new UiBlockSpecifier().ui {                                                 (2)
        closeModalAndUpdateBlock {                                              (3)
            show buildShowProjects(ecr), {
                menuIcon
                    ActionIcon.ADD,
                    Ecr2Controller.&projectsForm as MC, ecr.id
            }
        }
})
1 在模态窗口中触发保存对象的动作后,可以在同一个动作中关闭模态窗口并刷新页面元素
2 saveThenDisplayBlockOrRenderErrors 接收一个 UiBlockSpecifier 作为参数
3 closeModalAndUpdateBlock 会先关闭最近打开的模态窗口,然后应用页面更新
4 此处,名称包含在 ajaxBlockId 中的块将被更新

使用 ajaxBlock 时

待办事项(TODO)

  • 局部更新页面

  • 显示带有可编辑字段的对象

  • 显示图表

  • 将表格导出为 CSV

  • 将块渲染为 PDF

  • 将块渲染到邮件中

  • …​