LSPS documentation logo
LSPS Documentation
Validating a Record from a Form

In this tutorial, you will:

  • create a page that will add an entry to the database and log the event,
  • validate values of a record defined as user input in a form, and
  • start a process when a user performs some action on a page.

Requirements:

  • Create an order based on user input.
  • Make sure the user enters all data in the correct format.
  • Make sure the order is persisted only after the user submits it.

Important: This tutorial uses the forms Module to implement the GUI. This module is experimental and the resulting form is not compatible with the ui Modules, which is the previous and supported implementation.

Create a structure with the *order-placing module:*

  1. Open the Modeling perspective.
  2. Go to File -> New -> GO-BPMN Project.
  3. In the pop-up enter the project name OrderProcessing and click Next.
  4. In the Module name field, enter order-placing and click Next.
  5. In the imports dialog:
    1. Import the forms module: click Add, expand the Standard Library node and double-click forms.
    2. Remove the ui module.
  6. Click OK and Finish.

Create the data structure that will represent the Order:

  1. Right-click the order-placing Module and go to New -> Data Type Definition.
  2. Click Finish in the dialog box.
  3. Right-click the canvas in the opened graphical editor and select Shared Record.
    creatingsharedrecord.png
    Creating Order shared Record
  4. Name the Record Order.
  5. Select the Record and press Insert to insert a field into the Record. Define the following fields:
    • item of type String
    • price of type Decimal

Create the form for the Order page:

  1. Import the forms module.
  2. Right-click the order-placing Module and go to New -> Form Definition.
  3. Enter the name of your form OrderForm and select Use FormComponent-based UI to use the forms module.
  4. Create a form variable for the new order:
    1. In the Outline view, right-click the root node and go to New -> Variable.
    2. In its Properties View, define the variable properties:
      • Name: order
      • Type: Order
    3. Switch to the Methods tab and define a non-parametric form constructor that initializes the order variable to new Order().
  5. In the Form tab of the editor, insert the following components as displayed below and define the components' properties in their Properties views.
    • Form Layout
    • Text Field with properties:
      • ID: itemField
      • Caption: "Item:"
      • Binding: Reference to the field of the order variable &order.item
    • Decimal Field with properties:
      • ID: priceField
      • Caption: "Price:"
      • Binding: Reference to field of the order variable &order.price
    • Button:
      • ID: createButton
      • Caption: "Place Order"
      • Click Listener: Submit on click {e-> Forms.submit(); }
orderForm.png
Define the Order page as a document:

  1. Right-click the order-placing Module and go to New -> Document Definition.
  2. In the editor with the docs file, click Add and define the name and title of the document on the right.
  3. Define the page content in the UIDefinition:
    new OrderForm();

Currently you have a runnable model. When you run it and open the document, an order entry id created and persisted in the database: this happens when the order variable is instantiated. However, we want to create the entry only later after the order data has been validated. This problem can be solved with change proxies: Change proxies are intended to hold preliminary versions of shared records: their values are not persisted automatically. To persist the values and create the actual shared record, you need to explicitly merge the proxy.

  1. In the form constructor, initialize the order variable as a change proxy over the shared-record type: call proxy(Order).
        public OrderForm(){
            order := proxy(Order);
        }
    
  2. Define the merge of the proxy object in the Click Listener expression of the createButton:
    { e ->
         mergeProxies(false, order);
         Forms.submit()
    }
    
  3. Add a Cancel button that will navigate away from the screen, for example, { e -> new AppNavigation(code -> "todoList")}.

You still need to make sure that the user enters the required values into their order: Define constraints for the fields of the Order record and use them for validation of the form:

  1. Right-click the order-placing module and go to New -> Constraint Definition.
  2. In the editor with constraints, define the constraints as shown below.
    orderconstraints.png
    Constraints for the Order Record
  3. To check if the input meets the constraints, trigger validation of the order when the createButton is clicked: in the Click Listener expression, call the validate() function.
    { e ->
     def List<ConstraintViolation> errors :=  validate(order, null, null, null);
      if errors.isEmpty() then
         mergeProxies(false, order);
         Forms.submit();
      else
        //Displays the errors on the createButton
        //if the user never enters any value in the item
        //and price field:
        showDataErrorMessages(errors, createButton)
      end
    }
    
  4. Now the messages from constraints are all displayed on the createButton; Enable displaying of the messages on the respective input components by calling c.inferValidator(null) on the input fields.

Now we can upload the module to test the document:

  1. Make sure the server is running.
  2. Right-click the Module and go to Upload As -> Model
  3. Go to http://localhost:8080/lsps-application and log in.
  4. Click Documents in the menu on the left.
  5. Test the Order page.
    orderformdef.png
    Order page

Log Confirmation of Order

We will now extend the Order page to instantiate a process that will log a message when the user places an order.

Note that you could call the log() function from the UI definition when the user performs some action, too. However, for demonstration purposes, we will run a BPMN Process to do so. This will allow you to define potentially a complex flow of actions.

First, let's create the process:

  1. Create a logging module with a BPMN process.
  2. In the graphical editor with the process file, right-click into empty space on the canvas and under New select the None Start Event.
    processcontext.png
    Creating process elements
  3. Drag the quicklinker icon next to the None Start Event to a spot where you want to insert the next process element, the Log task.
    quicklinker.png
    Dragging quicklinker
  4. In the context menu, select Task and then Log task.
  5. On the Parameters tab in the Properties view of the task, define the message that should be logged and its message level.
  6. Connect the task to a Simple End Event.
    process.png
    Finished process
    Now we will add to the createButton in the Order document an expression that will create an instance of the logging model and trigger the process:
  7. Open the order form and add a call to the createModelInstance function into the Click Listener of the createOrder button. Note that you can pass a process entity from the call if the process needs to work with a shared record from the document, in our case the order.
    { e ->
     def List<ConstraintViolation> errors :=  validate(order, null, null, null);
      if errors.isEmpty() then
       //when the form is valid, the shared record instance is created based on the proxy Order object:
        mergeProxies(false, order);
        //creates a model instance of the order-placing module
        //which instantiates the log Process:
        createModelInstance(true, getModel("logging", "1.0"), order, null);
        Forms.submit();
     else
        showDataErrorMessages(errors, orderButton)
      end;
    
  8. Save the definitions and upload the modules.
  9. Go to the application and create an order from the document.

Let's check that the logging model with the process was instantiated:

  1. Back in PDS, switch to the Management perspective.
  2. Refresh the Models view: It now contains an entry of the loggin model instance.