# 字段变化

当表单上字段变化时需要完成表单上其他字段的一些联动可以使用FIELD_CHANGING事件。前端动态也能完成字段变化时其他字段的联动功能,但是如果变化的逻辑比较复杂或是需要到业务库里取一些业务数据填表的,那么就只有FIELD_CHANGING事件适合了。除了联动数据填表外,FIELD_CHANGING还可以用于一些复杂逻辑的表单校验,校验不通过时会在改变值的字段上出错误提示,也可以控制一些错误信息字段显示在表单上提示用户。

为了实现FIELD_CHANGING事件,需要在Messenger代码里覆写onFieldChanging方法,在工作流编辑器中也需要勾选Changing事件,在字段设置上也需要设置EventType属性为FIELD_CHANGING。

# 校验数据

那么先让我们来验证一个简单逻辑,就是请假开始时间需要早于结束日期。我们在工作流编辑器先把Changing事件勾上,然后将fieldBeginDate和fieldEndDate两个字段的EventType都设置为FIELD_CHANGING。

接下来在Messenger中添加onFieldChanging方法,以下代码中changedObject的作用后面再解释。校验不通过只需要抛出InfoPlusException即可,这样在前端会在发生变化的字段上冒出红色气泡提示错误。

 @Override
public InfoPlusResponse onFieldChanging(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    Object changedObject = null;
    // 如果发生FIELD_CHANGING事件的字段是fieldBeginDate或fieldEndDate
    if ("fieldEndDate".equals(e.getChangingField()) || "fieldBeginDate".equals(e.getChangingField())) {
        if (form.getBeginDate() != null && form.getEndDate() != null && form.getBeginDate().getTime() > form.getEndDate().getTime()) {
            throw new InfoPlusException("开始日期需要早于结束日期");
        }
        changedObject = form;
    }
    if (changedObject == null) {
        return null;
    }
    return new InfoPlusResponse(e, changedObject);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 数据联动

现在我们开始数据联动,这次的要求是当发现用户选择的类型是病假时在表单上显示本年度已经请病假的天数。为此我们需要表单上加一个提示信息的字段fieldTips,数据类型String,渲染类型Label,更新表单后在Messenger的表单对象上也增加这个属性,然后在fieldType上设置EventType为FIELD_CHANGING,最后添加以下代码到onFieldChanging方法。

@Override
public InfoPlusResponse onFieldChanging(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    Object changedObject = null;
    if ("fieldType".equals(e.getChangingField())) {
        if ("02".equals(form.getType().getCodeId())) {
            // 此处到业务数据库中获取已请事假天数并产生提示信息
            form.setTips("本年度已请病假3天");
        } else {
            // 其他请假类型清空提示信息
            form.setTips("");
        }
        changedObject = form;
    }
    if (changedObject == null) {
        return null;
    }
    return new InfoPlusResponse(e, changedObject);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

至此我们已完成了预想中的功能,可以调试发起一个流程看一下效果,现在当选择请假类型为病假时会出现已请假天数的提示。

# 重复节表

重复节表中字段的变化的FIELD_CHANGING事件的特殊之处在于onFieldChanging方法中获取变化的对象的方法,以及返回的表单对象。

先说一下这次的需求,我们要求用户在出差行程中每次修改日期后,如果行程简述还没写内容就把简述初始化为出差日期+"行程:",例如日期是2020-01-01,那么简述就初始化为"2020年1月1日行程:"

照惯例我们先把fieldTripDate字段的EventType设置为FIELD_CHANGING,然后修改onFieldChanging方法如下

@Override
public InfoPlusResponse onFieldChanging(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    Object changedObject = null;
    if ("fieldTripDate".equals(e.getChangingField())) {
        LeaveTrip trip = e.getChangingObject(form);
        if (trip.getTripDate() != null && StringUtils.isEmpty(trip.getTripDescription())) {
            trip.setTripDescription(new SimpleDateFormat("yyyy年M月d日").format(trip.getTripDate()) + "行程:");
        }
        changedObject = trip;
    }
    if (changedObject == null) {
        return null;
    }
    return new InfoPlusResponse(e, changedObject);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意这次获取修改对象的方法,前面数据联动章节里获取的是Leave对象

Leave form = e.toBean(Leave.class);
1

这次获取的是行程对象,以下代码能确保获取到的行程对象就是用户刚修改了日期的那行

LeaveTrip trip = e.getChangingObject(form);
1

还有一个不同之处是这次方法里将changedObject赋值为了LeaveTrip对象,最后返回的也是这个对象组装的InfoPlusResponse

...
changedObject = trip;
...
return new InfoPlusResponse(e, changedObject);
1
2
3
4

好了现在可以看一下效果了,正如我们预期的一样,修改日期的那行的行程简述字段被正确的初始化了。

当然这只是一个比较简单的情况,现实开发中我们还会遇到重复节表中字段修改后需要联动重复节表外层的字段,或者是这层重复节表内的更深层次的重复节表字段,所有的情况我们都总结在了这里 (opens new window)可以参考。

# 案例地址

download 流程链接
download 主表单模版
download Messenger代码