在做RAP的Fiori Elements开发时,用我们需要做一些功能,一个字段改变时,别一个字段立即变化,或者立即报错 ,对于值的变化,在RAP开发中可以在behavior使用determination来实现,而报错可使用validation来实现。在测试就会发现,这个改变或者报错,只是在后端的改变,不会影响前端(IE端)。而validation需要到保存时才会被触发。为了“立即”触发,这时就需要使用在behavior使用side effects了。side effects有许多的功能,更多细节可参考这里。
以下是一个使用的例子,
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
managed implementation in class zbp_i_delivery_h unique; strict ( 2 ); with draft; define behavior for ZI_Delivery_H alias DeliveryHeader persistent table zpot_delv_h draft table zpot_delv_h_d // ✅ draft 表 lock master total etag LastChangedAt //✅ 确保表中有此字段 authorization master ( instance ) etag master LastChangedAt { // 显式添加 create 和 delete 操作(至少 internal) //create; // //delete; // update (features: instance); field ( readonly ) DelvNo, CreatedBy, CreatedAt, CreatedByt, LastChangedAt; field ( mandatory ) DeliveryPerson, Phone, ExpectedDate, ExpectedTime; // 变更预计配送日期时,触发 DetermineEDATE 进行校验,前立即提示错误信息 determine action DetermineEDATE { validation ValidateEDate; } validation ValidateEDate on save { field ExpectedDate; create; update; } //此副作用,事实上只在投影时重定义才能真正起作用,但为了规范性和完整性,这里先放在主实体中定义 side effects { determine action DetermineEDATE executed on field ( ExpectedDate ) affects messages; } // 内置 draft actions(必须) draft action ( features : instance ) Edit; // ✅ 关键修改点,这里不给的话会导致没办法控制编辑的可用性, draft action Activate optimized; draft action Discard; draft action Resume; draft determine action Prepare; // 自定义操作 action (features: instance) approve result [0..1] $self; action (features: instance) cancelApproval result [0..1] $self; action (features: instance) confirmDelivery result [0..1] $self; action (features: instance) softDelete result [0..1] $self; action (features: instance) print; association _ITEM { create (features: instance); with draft; } mapping for ZPOT_DELV_H { DelvNo = DELV_NO; Status = STATUS; DeliveryPerson = DELIVERY_PERSON; Phone = PHONE; ExpectedDate = EXPECTED_DATE; ExpectedTime = EXPECTED_TIME; CreatedBy = CREATED_BY; CreatedByt = CREATED_BYT; CreatedAt = CREATED_AT; LastChangedAt = LAST_CHANGED_AT; } } //修改后的子实体 ZI_Delivery_I 部分: define behavior for ZI_Delivery_I alias DeliveryItem persistent table zpot_delv_i draft table zpot_delv_i_d //✅ draft 表 lock dependent by _header //✅ 确保表中有此字段 authorization dependent by _header //etag master LocalLastChangedAt //✅ 确保表中有此字段 late numbering { update (features: instance); delete (features: instance); determination DeterminePO on modify { field EBELN, EBELP; }//当修改采购订单号和行号时,触发 更新物料号、数量、单位等信息 //更改EBELN,EBELP时触触发 检查并立即提示消息 validation ValidatePO on save { field ebeln, ebelp; create; update; } determine action Determine_VALI_PO { validation ValidatePO; } //检查输入的配送数量不能大于可配送数量 validation ValidateDELVQTY on save { field DELVQTY; create; update; } determine action Determine_VALI_DELVQTY { validation ValidateDELVQTY; } //此副作用,事实上只在投影时重定义才能真正起作用,但为了规范性和完整性,这里先放在主实体中定义 side effects { // field EBELN affects field Matnr, field OrderQuantity, field Meins;"变更刷新,由于DETERMINE后面写了,这里就不用了 // field EBELp affects field Matnr, field OrderQuantity, field Meins;"变更刷新 determine action Determine_VALI_PO executed on field ( EBELN, EBELP ) affects field ( EBELN, EBELP, Matnr, OrderQuantity,DELVQTY, Meins ) ,messages ; determine action Determine_VALI_DELVQTY executed on field ( DELVQTY ) affects messages ; } field ( readonly ) DelvNo, ItemNo, Matnr, OrderQuantity, Meins; field ( features: instance ) Ebeln, Ebelp; field ( mandatory ) DelvQty; association _Header { with draft; } mapping for ZPOT_DELV_I { DelvNo = DELV_NO; ItemNo = ITEM_NO; Matnr = MATNR; DelvQty = Delv_Qty; Meins = MEINS; Ebeln = EBELN; Ebelp = EBELP; } } |
其中的代码:
|
1 2 3 4 5 6 7 |
// 变更预计配送日期时,触发 DetermineEDATE 进行校验,前立即提示错误信息 determine action DetermineEDATE { validation ValidateEDate; } validation ValidateEDate on save { field ExpectedDate; create; update; } //此副作用,事实上只在投影时重定义才能真正起作用,但为了规范性和完整性,这里先放在主实体中定义 side effects { determine action DetermineEDATE executed on field ( ExpectedDate ) affects messages; } |
实现一个功能,当字段ExpectedDate变化时会“立即”触发ValidateEDate较验,并显示检查结果到前端。在behavior加上上面内容后,在对应的behavior类中会生成一个对应的较验类方法,例如:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
METHODS ValidateEDate FOR VALIDATE ON SAVE IMPORTING KEYS FOR DeliveryHeader~ValidateEDate. ----------------------------------------------------------- METHOD ValidateEDate. READ ENTITIES OF ZI_Delivery_H IN LOCAL MODE ENTITY DeliveryHeader ALL FIELDS " 需要的业务字段 WITH CORRESPONDING #( KEYS ) RESULT DATA(LT_HEADER). DATA(today) = cl_abap_context_info=>get_system_date( ). "理论上这里只会有一行 LOOP AT LT_HEADER INTO DATA(Ls_HEADER). " 1. 清除该实例在 'VALIDATE_EDATE' 区域的所有旧状态消息 " 这一步是每次必执行的,用于清除任何残留的旧消息。 APPEND VALUE #( %tky = ls_header-%tky %state_area = 'VALIDATE_EDATE' ) " 只带区域,不带消息 TO reported-deliveryheader. IF Ls_HEADER-ExpectedDate < today. " 将不合规实例放入 failed,阻止保存 APPEND VALUE #( %tky = Ls_HEADER-%tky ) TO failed-DeliveryHeader. " 生成错误消息,并标记字段 APPEND VALUE #( %tky = Ls_HEADER-%tky %state_area = 'VALIDATE_EDATE' %msg = new_message( id = '00' number = '001' severity = if_abap_behv_message=>severity-error v1 = |预计发货日期 { Ls_HEADER-ExpectedDate } 不能早于当前日期 { today }| ) %element-ExpectedDate = if_abap_behv=>mk-on ) TO reported-DeliveryHeader. ENDIF. ENDLOOP. ENDMETHOD. |
这样实现了当字段改变时立即触发值的有效性检查。
事实上side effects还能实现更多的“立即”效果,可以参看这里。
field 触发,刷新复杂目标:可以刷新关联实体、权限等。示例如下:
|
1 2 3 4 |
side effects { field CarrierId affects entity _Travel; " 刷新关联实体 field CarrierId affects permissions(update); " 刷新更新权限控制 } |
$self 触发:只要实体本身被任何操作修改,就触发刷新。
|
1 2 3 |
side effects { $self affects field TotalPrice; " 实例修改时刷新总价 } |
action 触发:用户在前端点击 action 按钮时触发。
|
1 2 3 |
side effects { action RejectTravel affects field Status; " 点击某动作时刷新状态 } |
determine action 触发:字段变化时,先触发后端的 determine action 逻辑,然后刷新指定的目标
|
1 2 3 4 |
side effects { determine action CalculateTotal executed on field TravelPrice affects field TotalPrice, messages; " 触发动作并刷新字段和消息 } |
对于“修改EBELN/EBELP后刷新Matnr, OrderQuantity, Meins”的需求,使用简洁的 field ... affects field ... 写法是最合适的
