Logo

    Home

    Documentation

    Use Cases

    Training

    Applications

    Release Notes

    Pro-Code deep-dive: Call Backend-Logic from the UI

    Pro-Code deep-dive: Call Backend-Logic from the UI

    1 Context:

    🧠
    In this example we will write some ABL code and call that code from our UI by clicking on a Button. To make it more useful, we also want to pass in Data from the UI, and receive some Data back from the ABL code.

    For this task we will use the Screen “TrainingDay5_OrderOverview” and enhance the Form that is used in that Screen.

    2 Step by step guide:

    2.1 Implement a logic parameter

    First we will implement our Backend Business-Logic

    1. 👋In your ProCode Workspace create a new File in “/src/backend/BusinessLogic” -> and name it “OrderInfoParameter_<myName>.cls”
      1. 💡This will become the Parameter for the Logic we are going to implement.
    2. 👋 Start typing “b1-logicParameter” and select the template
      1. 💡 This will create a parameter-class for you with 3 sample Attributes. For our OrderInfo Business-Logic we want to receive a customer-number, and return the number of orders for that customer, as well as a message if there is any error. After defining those 3 Attributes our Parameter-Object will look like this:
    1. 👋Save the file.
      1. 💡 A corresponding .r file will be automatically created.

    2.2 Implement the Business Logic

    1. 👋 Create another File in “/src/backend/BusinessLogic” -> and name it “OrderLogic_<myName>.cls”
      1. 💡 In this class we will implement the actual logic.
    2. Start typing “b1-logicClass” and select the template.
      1. 💡 The code for method “myMethod” is created for you, and “myMethod” is automatically selected. Change this to the correct method name “getOrderInfo” by simply starting to type.
      2. 💡 B1 will automatically change all places in the code while you type. When you entered “getOrderInfo”, press TAB.
      3. 💡 B1 will automatically bring you to the next code-part that you need to change, the name of your Parameter-Class. Here we will use the Class we created in the previous step: OrderInfoParameter_<myName>.
      4. 💡Enter the name of your class and B1 will again automatically change it where necessary.
    3. 👋 Save your code.
      1. 💡 NOTE: If you get a syntax error, please add this line at the beginning of your file: using Consultingwerk.OERA.* from propath.
    4. 💡 In the Method (after the comment that says “enter your code here”) add the following logic:
     METHOD PUBLIC VOID getOrderInfo(poParameter AS getOrderInfoParameter):
        // enter your code here
        DEFINE VARIABLE iCount AS INTEGER NO-UNDO.
        iCount = RANDOM(1, 10).
    
        ASSIGN poParameter:numOrders = iCount.
        ASSIGN poParameter:Message = STRING(iCount) + " orders for customer " + STRING(poParameter:CustNum).
    
      END METHOD.
    1. Execute a b1 trim

    2.3 Implement the code in the UI that will call your ABL logic

    1. 👋 Go back to the Build.One Low-Code UI and open the Screen “TrainingDay5_OrderOverview”
    2. 👋 Open the Form “OrderForm_Training_Part5” (e.g. by using the “Open Master” feature in screen-designer, or using the “Forms” Desktop)
    3. 👋 In the Form-Designer select the Form itself (the root node in the tree), and then in the attributes set “Eventnamespace” to “#”
    4. 👋 Add a Button above the CustNum-Field, and set the “Enabled” Attribute to TRUE and the “Label” attribute to “get Order-Info”
    5. 👋For the “EventClick” Event add the following code:
    6. #.getOrderInfo(eventSource)
    7. 👋In the ribbon select the button “</> Open events file”. A new file is opened in the workspace IDE for your OrderForm_Training. Switch to the file if it is not automatically selected.
    8. 👋Start typing “b1” in the created file and see the different code-templates you can use. Please select the “eventFunction” and press enter
    9. 👋Change the function name to “getOrderInfo”
    10. 👋Change the Parameter to “myButton: akioma.swat.Button” to specify that your function expects to be called from a Button.
    11. 👋 In the body of the function, type “B1-callBackend” and select “callBackendSync”.
      1. 💡 B1 will add the code to call your backend logic. “Sync” means “Synchronously”: Your UI-code will wait until the Backend-Code has returned.
      2. 💡 You could also use “callBackendAsync”, then your UI will immediately go to the next statement, and the backend logic will run in parallel (Asynchronoously).
      3. 💡 In our case, we want to work with the Result from our Backend-Code, hence we need to wait till it is finished. So “callBackendSync” is what we need for our use-case.
    12. 👋 Provide the correct Values for “name” and “methodName” and change the Function to look like this:
      1. 💡 (Hint add the async parameter in the eventFunction in order to use the await parameter)

    Full Code Example:

    export async function getOrderInfo(myButton: akioma.swat.Button) {
        
      const oResult = await akioma.swat.App.invokeServerTask({
        name: 'BusinessLogic.OrderLogic_<YourName>',
        methodName: 'getOrderInfo',
        paramObj: { plcParameter: {"custNum": 1} },
      });
      
      akioma.swat.Message.informationMessage (`Result: ${oResult.plcParameter.Message} `)
      
    }

    Here we have the parameters for our Backend-Logic hardcoded.

    💡 To see your interim result do the following steps

    • Click control + S to save and compile your result
    • Go back to B1
    • Refresh the page and empty the cache
    • Launch your screen
    • Click on the button

    13. 👋 In the next step we want to pass in the actual customer. For this, we read the data from the UI. Change the code to look like this:

    💡Here, we figure out the form of the Button. Then we use the Blueprint to find the corresponding datasource. The getLink() function gives you at runtime access to the Flow-Part of the screen (The “Flow” Tab in the Screen-Designer).

    💡Note: Instead of using the CustNum, one would use the Build.One “Handle”-Concept. Every Record has a Field “SelfHdl” which contains a character that uniquely identifies the record.

    3 Explanation:

    ☝
    In this exercise we implemented Backend-Logic and wrote corresponding UI Logic using the CLAPI (Client-Logic API). In our UI-Code we made use of the Blueprint in order to make our application future-proof

    4 All working Code files as example

    Order Info Parameter

    Order Logic

    Forntend Class Hard Coded

    export async  function getOrderInfo(myButton: akioma.swat.Button) {
      
      const oResult = await akioma.swat.App.invokeServerTask({
        name: 'BusinessLogic.OrderLogic_Alex',
        methodName: 'getOrderInfo',
        paramObj: { plcParameter: {"custNum": 1} },
      });
      
      akioma.swat.Message.informationMessage (`Result: ${oResult.plcParameter.Message} `)

    Frontend Class Dynamic

    Logo
    BLOCK-LEVEL ON ERROR UNDO, THROW.
    
    CLASS <yourFileName>
      INHERITS Consultingwerk.JsonSerializable:
    
      /* Input properties */
      { Akioma/Swat/JsonSerializableProperty.i custNum integer }.
    
      /* Output properties */
      { Akioma/Swat/JsonSerializableProperty.i numOrders integer  }.
      { Akioma/Swat/JsonSerializableProperty.i Message CHARACTER }. 
    
      CONSTRUCTOR PUBLIC <yourFileName>():
        SUPER().
        THIS-OBJECT:AddSerializableProperties("{&SerializableProperties}").
      END CONSTRUCTOR.
    END CLASS.
    export async function getOrderInfo(myButton: akioma.swat.Button) {
    
      const myForm       = myButton.form as akioma.swat.Form;
      const myDatasource = myForm.getLink("DISPLAY:SRC") as akioma.swat.DataSource;
      
      const oResult = await akioma.swat.App.invokeServerTask({
        name: 'BusinessLogic.OrderLogic_YourName',
        methodName: 'getOrderInfo',
        paramObj: { plcParameter: {"custNum": myDatasource.getValue("custnum")} },
      });
      
      akioma.swat.Message.informationMessage (`Result: ${oResult.plcParameter.Message} `)
      
    }
    BLOCK-LEVEL ON ERROR UNDO, THROW.
    
    CLASS BusinessLogic.OrderInfoParameter_Alex
      INHERITS Consultingwerk.JsonSerializable:
    
      /* Input properties */
      { Akioma/Swat/JsonSerializableProperty.i custNum integer }.
    
      /* Output properties */
      { Akioma/Swat/JsonSerializableProperty.i numOrders integer  }.
      { Akioma/Swat/JsonSerializableProperty.i Message CHARACTER }. 
     
      CONSTRUCTOR PUBLIC OrderInfoParameter_Alex():
        SUPER().
        THIS-OBJECT:AddSerializableProperties("{&SerializableProperties}").
      END CONSTRUCTOR.
    END CLASS.
    using BusinessLogic.* from propath.
    using Consultingwerk.OERA.* from propath.
    
    BLOCK-LEVEL ON ERROR UNDO, THROW.
    
    CLASS BusinessLogic.OrderLogic_Alex
      IMPLEMENTS Consultingwerk.OERA.IBusinessService, Consultingwerk.OERA.IBusinessTaskCatalogInfo:
    
      METHOD PUBLIC Consultingwerk.OERA.IBusinessTaskCatalogData GetCatalogData():
        DEFINE VARIABLE oCatalog AS Consultingwerk.OERA.BusinessTaskCatalogData NO-UNDO.
    
        oCatalog = NEW Consultingwerk.OERA.BusinessTaskCatalogData(THIS-OBJECT:GetClass():TypeName,
          "getOrderInfo", GET-CLASS(OrderInfoParameter_Alex)).
    
        RETURN oCatalog.
      END METHOD.
    
      METHOD PUBLIC VOID getOrderInfo(poParameter AS OrderInfoParameter_Alex):
        // enter your code here
        DEFINE VARIABLE iCount AS INTEGER NO-UNDO.
        iCount = RANDOM(1, 10).
    
        ASSIGN poParameter:numOrders = iCount.
        ASSIGN poParameter:Message = STRING(iCount) + " orders for customer " + STRING(poParameter:CustNum).    
      END METHOD.
    END CLASS.
    
    export async  function getOrderInfo(myButton: akioma.swat.Button) {
      
      const myForm       = myButton.form as akioma.swat.Form;
      const myDatasource = myForm.getLink("DISPLAY:SRC") as akioma.swat.DataSource;
      
      const oResult = await akioma.swat.App.invokeServerTask({
        name: 'BusinessLogic.OrderLogic_Alex',
        methodName: 'getOrderInfo',
        paramObj: { plcParameter: {"custNum": myDatasource.getValue("custnum")} },
      });
      
      akioma.swat.Message.informationMessage (`Result: ${oResult.plcParameter.Message} `)
      
    }