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

Displaying the Applicant List

Create a form with the list of applicants:

  1. Create the form ApplicantGrid.
  2. Design the form:
    1. Insert a Vertical Layout.
    2. Insert a Grid.
  3. Set the Grid properties:
    1. Set the ID to applicantListGrid.
    2. Set the data source to Type and its value to the record type Applicant.
  4. Insert the Grid Column for applicant properties:
    • Set the Value Provider to Property Paths.
    • Set the values of value providers to the Applicant fields: Applicant.firstName, Applicant.lastName, and Applicant.level.
    • For the Applicant.level, set the renderer to Enumeration.

Displaying and Editing Applicant Details

To display the applicant data in a popup and to create a new applicant, you will create not only the form for the popup but also an object that will hold a copy of the applicant data. This will allow the user to close the popup without saving any changes they might have made. Were you to use the applicant object directly in the popup, the changes in the form would be applied immediately on the object.

Create the form for the details:

  1. Create a form definition ApplicantDetailPopup.
  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 the form variable for the proxy mechanism, the applicantProxySet form variable of type RecordProxySet.
  4. 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.
  5. Define a parametric form constructors in the methods file of the form: Pass it the applicant parameter and store it in its proxy form variable so the popup can work with a proxy copy of a particular applicant:
       public ApplicantDetailPopup(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 ->

Now you need to display the data of an applicant in the popup when the user clicks an Edit button:

  1. Insert a Grid Column that will render the Edit button that will open the public Popup with the row data:
  2. Set the column details:
    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 ApplicantDetailPopup appDetailPopup := new ApplicantDetailPopup(clickedApplicant);
          //display the popup:
          //set listener on the popup, so the grid with applicants is updated when the popup closes:
          appDetailPopup.setPopupCloseListener({ e->applicantListGrid.refresh()});

Creating a New Applicant

To allow the user to create a new applicant from the form, do the following:

  1. Add to the methods of the ApplicantDetailPopup form, a non-parametric constructor that initializes the applicant variable to a proxy of the Applicant type:
    public ApplicantDetailPopup(){
      //proxy set init:
      applicantProxySet := createProxySet(null);
      //change proxy diretly over the Applicant type:
      applicant := applicantProxySet.proxy(Applicant)
  2. In the ApplicantGrid form, insert a New Applicant button.
  3. Define its click action so it creates and displays the public popup using the non-parameteric constructor:
    { click:ClickEvent ->
        //creates the public popup with the non-parametric constructor:
        def ApplicantDetailPopup appDetailsPopup := new ApplicantDetailsPopup();
        //refreshes the grid so it contains the new applicant:
        appDetailPopup.setPopupCloseListener({ e->applicantListGrid.refresh()});
    Now you can use the ApplicantGrid form in documents or user tasks as their UIDefinition.

You can download the tutorial example here.