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.
  1. Create a structure with an executable 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. Click OK and Finish.
  2. Create the data definition with the Order shared record with the following fields:
    • item of type String
    • price of type Decimal
  3. Create the form which will be the content of the Order page:
    1. Create a form definition; make sure to select Use FormComponent-based UI so the forms module is used as the form implementation.
    2. Create a form variable that will hold the new order with the properties:
      • Name: order
      • Type: Order
    3. On the Methods tab, define a form constructor that initializes the variable.
          public OrderForm(){
            order := new Order();
          }
      
    4. 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
  4. Create a document definition with the Order document: set the UIDefinition to return your form:
    new OrderForm();

At this point, you have a runnable model: if you run it, you will realize that the order entry in the database is created at the moment the model instance is created; which is at the moment you open the Document and the order variable is instantiated. However, we want to create the entry only after the order data is validated so no bogus data is persisted in the database and add a Cancel button to our form. This problem can be solve with Change Proxies: Change proxies hold preliminary versions of shared Records: their values are not reflected in the database. Proxies exist in sets called proxy sets, which serve primarily to define their proxy level. To apply the values of proxies and create the actual shared record instances, you merge their proxy set.

Note that you can create a change proxy for a shared record type; the shared record instance does not need to exist when you are creating the proxy. The shared record instance is created on merge.

  1. Make the order a proxy:
    1. Create a form variable recProxySet of type RecordProxySet and initialize it from the form constructor before the order variable.
      recProxySet := createProxySet(null);
    2. Also from the form constructor, adjust the initialization of the order variable to be a change proxy over the order shared-record type:
      order := recProxySet.proxy(Order);
    3. In the Click Listener expression of the createButton, add the merge of the proxy set with the proxy object.
      { e ->
           recProxySet.merge(false);
           Forms.submit()
      }
      
    4. Add a Cancel button that will navigate away from the screen, for example,
      { e -> new AppNavigation(code -> "todoList")}
  2. Validate the order data:
    1. Create a constraint definition and define the constraints for the fields of the Order record.
      orderconstraints.png
      Constraints for the Order Record
    2. To check if the input meets the defined constraints, trigger validation of the order on click of the createButton: in the Click Listener expression, call the validate() function on the order variable and handle the returned error messages:
      { e ->
       def List<ConstraintViolation> errors :=  validate(order, null, null, null);
        if errors.isEmpty() then
          recProxySet.merge(false);
          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
      }
      
    3. 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.
  3. Upload the module and 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 Process

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 simply 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, which could potentially execute a more complex flow of actions.

  1. Create the logging 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.
    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
  2. Instantiate the logging model from the createButton: To the Click Listener of the createButton, add the createModelInstance() function call 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:
        recProxySet.merge(false);
        //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;
    
  3. Save the definitions and upload the modules.
  4. To upload the logging module automatically with the order-placing module, import it to the order-placing module.
  5. 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 logging model instance.
    modelinstancedetails.png
    Model Instance details and live diagram\; note the process entity property in the properties tree node.