1 Context:
In this example, we will write our own ABL server logic to enhance the data fetched through an ABL datasource. We will populate the customer datasource ‘Comments’ field with the number of orders, the number of shipped orders and the balance of each customer in part.
2 Step by step guide:
- For this task we will use the screen we used for the Frontend button again. Please use your copy of “TrainingDay5_OrderOverview”
- In your ProCode Workspace create a new folder
src/backend/Training/
- Create a new file in that folder
src/backend/Training/CustomerEventHandler.cls
- Start typing “b1-datasourceEventhandler” and select the template, then save your code by pressing “CTRL+ S”
- Navigate back to your Low-Code Workspace and go to “Integrate” -> “Data” -> “Datasource” and select the button “Generate Dataset-Definiton” in the toolbar
- Search for the “Data Source Object” -> “CustomerDSO” and click on “Generate Definition”
- Copy the “Dataset Definition”
- Navigate back to your Pro-Code Workspace and create a new file in your newly created folder
src/backend/Training/
and call itdsCustomer.i
and paste your copied “Dataset Definition” in there, then press “Strg + S” - Include the dsCustomer.i in the class:
CLASS Training.CustomerEventHandler
INHERITS Akioma.Swat.OERA.Dynamic.BaseServerEventHandler:
{ <YourFolder>/dsCustomer.i &ACCESS="PRIVATE" }
- Insert the term “dsData” in the dataset
CONSTRUCTOR CustomerEventHandler():
SUPER(DATASET dsData :HANDLE).
THIS-OBJECT:TriggerOnBeforeSave = TRUE.
THIS-OBJECT:TriggerOnAfterFetch = TRUE.
END CONSTRUCTOR.
- Write the following code for your method:
METHOD PROTECTED OVERRIDE VOID OnAfterFetch():
DEF VAR iCount AS INT NO-UNDO.
DEF VAR iNumShipped AS INT NO-UNDO.
/* go through every CustTable record read from the DB */
FOR EACH eCustomer:
ASSIGN iCount = 0 iNumShipped = 0.
// for each fetched Customer, go through all contacts in the DB
FOR EACH sportsdb.order WHERE sportsdb.order.custNum = eCustomer.custNum NO-LOCK:
iCount = iCount + 1.
IF sportsdb.order.orderStatus = "Shipped" THEN ASSIGN iNumShipped = iNumShipped + 1.
END.
ASSIGN eCustomer.Comments = SUBSTITUTE("Customer has &2 orders, &3 shipped. Balance is $ &4", eCustomer.CustNum, STRING(iCount, "99"), STRING(iNumShipped, "99"), eCustomer.Balance).
END.
END METHOD.
- Now press “Strg + S” and execute a “b1 trim” in the terminal -> This will restart the “PASOE” without loosing your current session
- Now go back to your Low-Code Workspace and navigate to “Integrate” -> “Data” -> “Datasource”
- Search for the “CustomerDSO” and open the designer for it
- Search for the attribute “ServerEventHandler” in the “Attributes” panel and fill in the value ->
Training.CustomerEventHandler
, then select “Save” - Navigate to “Design” -> “Screens” and launch your screen to see the result
Full Code Example:
BLOCK-LEVEL ON ERROR UNDO, THROW.
CLASS Training.CustomerEventHandler
INHERITS Akioma.Swat.OERA.Dynamic.BaseServerEventHandler:
{ Training/dsCustomer.i &ACCESS="PRIVATE" }
CONSTRUCTOR CustomerEventHandler():
SUPER(DATASET dsData:HANDLE).
THIS-OBJECT:TriggerOnBeforeSave = TRUE.
THIS-OBJECT:TriggerOnAfterFetch = TRUE.
END CONSTRUCTOR.
METHOD PROTECTED OVERRIDE VOID OnBeforeSave():
// enter before save code here
END METHOD.
METHOD PROTECTED OVERRIDE VOID OnAfterFetch():
DEF VAR iCount AS INT NO-UNDO.
DEF VAR iNumShipped AS INT NO-UNDO.
/* go through every CustTable record read from the DB */
FOR EACH eCustomer:
ASSIGN iCount = 0 iNumShipped = 0.
// for each fetched Customer, go through all contacts in the DB
FOR EACH sportsdb.order WHERE sportsdb.order.custNum = eCustomer.custNum NO-LOCK:
iCount = iCount + 1.
IF sportsdb.order.orderStatus = "Shipped" THEN ASSIGN iNumShipped = iNumShipped + 1.
END.
ASSIGN eCustomer.Comments = SUBSTITUTE("Customer has &2 orders, &3 shipped. Balance is $ &4", eCustomer.CustNum, STRING(iCount, "99"), STRING(iNumShipped, "99"), eCustomer.Balance).
END.
END METHOD.
END CLASS.
3 Explanation:
Every time data is retrieved, our defined event handler is called and our defined logic is executed. This demonstrates how easy it is to integrate and use custom code in the backend. The message gets generated in the defined field with every fetch.