LSPS documentation logo
LSPS Documentation
Editing Data in a Popup with Conflict Check

Required result: The user accesses a Grid with entries of a shared Record type via a document. When they click the Edit column in a row, a Popup with editable data of the row is displayed. They can either save the changes or drop the changes. If someone else has edited the applicant in the meantime, log a notification.

The Popup form is reusable: the same form is used on two occasions: when creating a new applicant and when editing an existing applicant:

We will use the Applicant shared record displayed below.

Applicant record with the Level enumeration used in the Applicant Record field

Setting up Optimistic Locking

To prevent silent overwrite of applicant data, let us enabled versioning of the Applicant record:

  1. Create a version field of type Integer in the Applicant record.
  2. On the DB Mapping of its Properties, select Version.

Creating the Public Popup

First, create the form the with popup:

  1. Create a form definition ApplicantDetailsPopup.
  2. In the Outline view, select the form root component and, in its Properties view, set its type to forms::Popup and make sure it is public.
  3. Create form variable for the proxy mechanism:
    1. Create the applicantProxySet form variable, which will hold the set for the applicant proxy.
    2. Create the applicant form variable of type Applicant, which will hold the data of the new or edited applicant: right-click the root node in the Outline view and select New > Variable; set its name to applicant and type to Applicant.
  4. Create the applicantProxySet form variable, which will hold the set for the applicant proxy.
  5. Define the form constructors in the methods file of the form:
    • a non-parametric constructor we will use when creating a new applicant:

      It initializes the applicant variable to a proxy of the *Applicant** type.

         public ApplicantDetailsPopup(){
           //proxy set init:
           applicantProxySet := createProxySet(null);
           //change proxy diretly over the Applicant type:
           applicant := applicantProxySet.proxy(Applicant)
    • a parametric constructor will for editing an existing applicant:

      It takes the applicant parameter and stores its proxy the form variable.

         public ApplicantDetailsPopup(Applicant applicant){
           applicantProxySet := createProxySet(null);
           //change proxy of the applicant object is assigned
           //so that changes on the applicant are stored only after the user clicks Save:
           this.applicant := applicantProxySet.proxy(applicant)
  6. Design the form tree: keep in mind it represents the content of a popup; bind the input fields to the application variable as appropriate.
  7. Define the click listener expression on the Save button:
    { click:ClickEvent ->
          //apply the changes if the record has not been changed in the meantime;
          try applicantProxySet.merge(true)
          catch "com.whitestein.lsps.common.OptimisticLockException" ->
              //log a message if the record has been changed:
              log("failed to merge changes", 100);
               caption -> "Conflict on merge",
               description -> "Your changes could not be saved: the data was changed."
          //close the popup:
  8. Define the click listener expression on the Cancel button:
    { click:ClickEvent ->

Using the Public Popup

Create the ApplicantList form with the list of applicants with the following components:

  1. Insert a Vertical Layout.
  2. Insert a Grid:
    1. In its properties:
      1. Set ID to applicantListGrid.
      2. Set the data source to Type and its value to the record type Applicant.
    2. Insert a Grid Column for each applicant property:
      • Set the Value Provider to Property Paths.
      • Set the values of value providers to the Applicant fields, such as
      • Set the appropriate Renderer, for example, for the Applicant.level, set the Enumeration renderer.
    3. Insert a Grid Column that will render the Edit button that will open the public Popup with the row data:
      1. Set Value Provider to Constant with the value "Edit".
      2. Set Renderer to Button.
      3. Below define the button action so that it creates and displays the popup with the data of the edited applicant:
        { clickedApplicant:Applicant ->
            //create the popup with details:
            def ApplicantDetailsPopup appDetailsPopup := new ApplicantDetailsPopup(clickedApplicant);
            //display the popup:
            //set listener on the popup, so the grid with applicants is updated when the popup closes:
            appDetailsPopup.setPopupCloseListener({ e->applicantListGrid.refresh()});
  3. Below the Grid insert a Create Applicant Button that will create and display the public popup using the non-parameteric constructor:
    { click:ClickEvent ->
        //creates the public popup with the non-parametric constructor:
        def ApplicantDetailsPopup appDetailsPopup := new ApplicantDetailsPopup();
        //refreshes the grid so it contains the new applicant:
        appDetailsPopup.setPopupCloseListener({ e->applicantListGrid.refresh()});
    Resulting form
  4. Use the ApplicantList form in documents or user tasks as their UIDefinition.

You can download the tutorial example here.