이전에 포스팅했던 툴바 버튼을 새로 생성해준뒤 행추가, 행삭제 기능을 넣는 것이 아닌 기존 툴바에 생성되어있는 버튼을 활용해 행추가, 행삭제 기능을 구현해본다.
CREATE OBJECT GR_EVENTS.
SET HANDLER GR_EVENTS->HANDLE_DATA_CHANGED FOR GO_GRID.
IF GV_METHOD = GC_DISPLAY.
GO_GRID->SET_READY_FOR_INPUT( 0 ).
ELSE.
CALL METHOD GO_GRID->REGISTER_EDIT_EVENT
EXPORTING
I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_MODIFIED.
GO_GRID->SET_READY_FOR_INPUT( 1 ).
이런식으로 ALV를 INPUT을 1로 주면 편집모드로 전환되고, 행추가 행삭제 버튼도 생긴다. 여기서 클릭한 Row로 새로 행추가가 되는 버튼은 exclude해주고 맨 아래에 행추가가 되는 버튼만 남겨준다.
ER_DATA_CHANGED->MT_DELETED_ROWS[].
ER_DATA_CHANGED->MT_INSERTED_ROWS[].
추가되거나 삭제된 Row가 들어가는 메소드를 사용해 진행할건데, 클릭한 Row로 새로 행추가가 되는 버튼은 해당 Row가 아닌 마지막 Row가 MT_INSERTED_ROWS에 들어가기 때문에 제외한다.
Data changed Event
FORM ALV_DATA_CHANGED
FORM ALV_DATA_CHANGED
USING SENDER TYPE REF TO CL_GUI_ALV_GRID
ER_DATA_CHANGED TYPE REF TO CL_ALV_CHANGED_DATA_PROTOCOL
E_ONF4_AFTER TYPE C.
DATA: LS_MODI TYPE LVC_S_MODI.
DATA: LT_MODIS TYPE LVC_T_MODI.
DATA: LT_FIELD TYPE TYP_T_FIELDNAME,
LV_FNAME TYPE FIELDNAME.
FIELD-SYMBOLS <WA> LIKE GT_DISP.
LT_MODIS[] = ER_DATA_CHANGED->MT_GOOD_CELLS[].
DATA : LT_DELITEM TYPE LVC_T_MOCE.
DATA : LT_INSITEM TYPE LVC_T_MOCE.
LT_DELITEM[] = ER_DATA_CHANGED->MT_DELETED_ROWS[].
LT_INSITEM[] = ER_DATA_CHANGED->MT_INSERTED_ROWS[].
LT_DELITEM[]
, LT_INSITEM[]
삭제되거나 추가된 행의 Row가 들어간다.
IF SENDER = GO_GRID.
LOOP AT LT_DELITEM INTO DATA(LS_DELITEM).
READ TABLE GT_DISP INDEX LS_DELITEM-ROW_ID.
MOVE-CORRESPONDING GT_DISP TO GT_DELE.
APPEND GT_DELE.
ENDLOOP.
스탠다드 행삭제버튼은 GT_DISP에서 삭제를 해버리는지 저장로직에서 GT_DISP를 보면 지워져있다. 그래서 삭제한 행을 따로 인터널테이블에 담아둔뒤 저장로직에서 DELETE한다.
LOOP AT LT_INSITEM INTO DATA(LS_INSITEM).
CLEAR GT_DISP.
GT_DISP-MARK = GC_CREATE.
APPEND GT_DISP.
ENDLOOP.
따로 APPEND를 해주지 않아도 저장로직에서 GT_DISP 보면 데이터 추가가 되어있는데, 새로 추가한 행에 MARK값을 주기위해 직접 APPEND해준다.
LOOP AT LT_MODIS INTO LS_MODI.
READ TABLE GT_DISP INDEX LS_MODI-ROW_ID ASSIGNING FIELD-SYMBOL(<FS_DISP>).
CHECK SY-SUBRC = 0.
CASE LS_MODI-FIELDNAME.
WHEN 'VKORG'.
SELECT SINGLE VTEXT
FROM TVKOT
INTO @<FS_DISP>-VKORGT
WHERE SPRAS = @SY-LANGU
AND VKORG = @LS_MODI-VALUE.
APPEND 'VKORGT' TO LT_FIELD.
~~~
ENDCASE.
IF <FS_DISP>-MARK IS INITIAL.
<FS_DISP>-MARK = GC_MODIFY.
ENDIF.
APPEND 'MARK' TO LT_FIELD.
MARK가 비어있지 않은 경우는 행추가된 Row이고, SAVE 로직에서 변경 Row랑 처리 로직이 다르기 때문에 비어있을때만 변경 MARK를 준다.
PERFORM ALV_MODIFY_CELL USING ER_DATA_CHANGED
LT_FIELD
LS_MODI-ROW_ID
<FS_DISP>.
ENDLOOP.
ENDIF.
ENDFORM.
FORM ALV_MODIFY_CELL
FORM ALV_MODIFY_CELL
USING ER_DATA_CHANGED TYPE REF TO CL_ALV_CHANGED_DATA_PROTOCOL
P_IT_FIELD TYPE TYP_T_FIELDNAME
P_IV_ROW_ID
PS_DATA.
DATA: LV_FIELDNAME TYPE FIELDNAME.
DATA: LV_FNAME TYPE LVC_FNAME.
FIELD-SYMBOLS <FS> TYPE ANY.
LOOP AT P_IT_FIELD INTO LV_FIELDNAME.
CONCATENATE 'PS_DATA-' LV_FIELDNAME INTO LV_FNAME.
ASSIGN (LV_FNAME) TO <FS>.
CALL METHOD ER_DATA_CHANGED->MODIFY_CELL
EXPORTING
I_ROW_ID = P_IV_ROW_ID
I_FIELDNAME = LV_FIELDNAME
I_VALUE = <FS>.
ENDLOOP.
ENDFORM.
PAI
FORM SAVE_DATA
FORM SAVE_DATA .
CALL METHOD GO_GRID->CHECK_CHANGED_DATA. "변경이 일어났는지 체크
DATA: LS_MODI TYPE ZSDT_WARRANTY.
"신규 생성시 키값 중복 CHECK
SELECT 키필드1 키필드2 FROM 테이블
INTO TABLE @DATA(LT_KEY).
SORT LT_KEY BY 키필드1 키필드2.
LOOP AT GT_DISP WHERE MARK IS NOT INITIAL.
"키값 입력 CHECK
IF GT_DISP-키필드1 IS INITIAL OR
GT_DISP-키필드2 IS INITIAL .
MESSAGE I000 DISPLAY LIKE 'E'. "필수 필드 입력하세요
RETURN.
ENDIF.
CASE GT_DISP-MARK.
WHEN GC_CREATE.
READ TABLE LT_KEY INTO DATA(LS_KEY) WITH KEY 키필드1 = GT_DISP-키필드1
키필드2 = GT_DISP-키필드2 BINARY SEARCH.
IF SY-SUBRC EQ 0.
MESSAGE I000 DISPLAY LIKE 'E'. "중복되는 데이터 존재
RETURN.
ELSE.
GT_DISP-ERDAT = SY-DATUM.
GT_DISP-ERNAM = SY-UNAME.
GT_DISP-ERZET = SY-UZEIT.
MOVE-CORRESPONDING GT_DISP TO LS_MODI.
LS_MODI-MANDT = SY-MANDT.
MODIFY DB테이블 FROM LS_MODI.
ENDIF.
WHEN GC_MODIFY.
GT_DISP-AEDAT = SY-DATUM.
GT_DISP-AENAM = SY-UNAME.
GT_DISP-AEZET = SY-UZEIT.
MOVE-CORRESPONDING GT_DISP TO LS_MODI.
MODIFY DB테이블 FROM LS_MODI.
ENDCASE.
CLEAR : GT_DISP-MARK, LS_MODI.
MODIFY GT_DISP.
IF SY-SUBRC EQ 0.
MESSAGE S000.
ELSE.
MESSAGE I000 DISPLAY LIKE 'E'.
ENDIF.
ENDLOOP.
DELETE DB테이블 FROM TABLE GT_DELE[].
IF SY-SUBRC EQ 0.
MESSAGE S000. "저장되었습니다
CLEAR: GT_DELE, GT_DELE[].
ELSE.
MESSAGE I000 DISPLAY LIKE 'E'. "저장을 실패했습니다
ENDIF.
ENDFORM.
DELETE처럼 변경된 데이터를 인터널테이블에 담고 한번에 MODIFY해도 되지만, 중간에 잘못된 데이터가 있어 오류가 날경우 이미 지나간 데이터는 MARK가 지워졌기 때문에 다시 SAVE를 눌렀을때 오류가 나기 이전 데이터들은 변경되지 않는다. 그래서 한줄씩 MODIFY 해줌.
행을 선택하고 삭제할때 유의할점. 내림차순 필수!
FORM alv_cl_toolbar_del_row .
DATA : lt_index_rows TYPE lvc_t_row,
lt_row_no TYPE lvc_t_roid,
ls_row_no TYPE lvc_s_roid.
DATA : lv_lines TYPE i.
CALL METHOD gv_alv_grid1->get_selected_rows
IMPORTING
et_index_rows = lt_index_rows
et_row_no = lt_row_no.
DESCRIBE TABLE lt_row_no LINES lv_lines.
IF lv_lines < 1.
MESSAGE i014(zhr).
RETURN.
ELSE.
SORT lt_row_no BY row_id DESCENDING.
LOOP AT lt_row_no INTO ls_row_no.
READ TABLE gt_disp INTO gs_disp INDEX ls_row_no-row_id.
gs_disp-mark = 'D'.
MODIFY gt_disp FROM gs_disp INDEX ls_row_no-row_id.
MOVE-CORRESPONDING gs_disp TO gs_del.
APPEND gs_del TO gt_del.
DELETE gt_key INDEX ls_row_no-row_id.
ENDLOOP.
DELETE gt_disp WHERE mark = 'D'.
ENDIF.
ENDFORM.
SORT lt_row_no BY row_id DESCENDING.
꼭 내림차순을 한뒤 삭제해줘야한다. 그렇지 않으면 ROW가 뒤죽박죽되버림.
Index로 삭제하면 안되는 이유!!!
사용자가 한번에 추가, 삭제를 하면 Index가 뒤죽박죽 되어버리기 때문에 Mark를 주고, 저장할때 한번에 modify, delete를 처리하는 방법을 권장한다.
'ABAP' 카테고리의 다른 글
ALV Refresh시 Layout 재설정 (SET_FRONTEND_LAYOUT) (0) | 2023.03.01 |
---|---|
Pop-up ALV (0) | 2023.02.27 |
View Event (0) | 2023.02.24 |
Parameter List box (0) | 2023.02.24 |
SELECTION SCREEN Search Help F4 (0) | 2023.02.24 |
댓글