Working with Services - calling Services in a Loop

Description

This sample allows a user to sign-up for a series of workshops.  The workshops only accept a certain number of applicants and the form cannot be submitted if the capacity of one of the workshops is filled.

Purpose

I have created this application to demonstrates how to restrict a form from being submitted based on previously submitted responses, and to demonstrate how to call a service in a loop correctly.

The Form

How It Works

The user selects the workshops they are interested in and then clicks the "Check Workshop Availability" button.  This button kicks off a process that calls a service for each item in the check list that queries the existing submissions and returns a count.  If the count of submissions for any workshop is >= 5 then the field is set to invalid and the submit button is disabled.

Let's look at all the parts that make this application function:

1. I need a few fields that will be used to store temporary information to interact with my service call that will look up the workshop application count.

2. I need the service that will look up the workshop and return the number of submitted records.

- The service is calling the Search operation for this form.

- I am passing the temp workshop field as an input linked to the Workshops field in the service.

- Since a checklist value is a concatenation of all the selected values (i.e. value1__#__value2__#__) I have to modify the default search operator.  So I link a constant value of contains.  This way the service will return all the records where the check list contains the workshop being searched.

- The output is the Number of records parameter and I link this to the Count field.

3. I need the code that will trigger the service call for each of the check list selections.  This is the tricky part.

In the onClick event of the button we have the code:


BO.F_Paragraphtext.setValue("");

//reset the capExceededFlag
form.getBO().F_CapacityExceeded.setValue("false");

//get array of selected options from the check list
app.getSharedData().selected_opts = BO.F_WorkShopList.getValue().split("__#__");

//This is a counter that will keep track of what record we have just processed
app.getSharedData().currentRecord = 0;
app.getSharedData().errString = "";

//copy the first selected value (from the array) into the temporary field and call the service
BO.F_tempWorkshop.setValue(get(app.getSharedData().selected_opts, app.getSharedData().currentRecord));

//call the service to get the submission count for this workshop
form.getServiceConfiguration("SC_GetWorkshopCount").callService();



In the onLoad of the form I have a service call listener which executes once the service has completed successfully.


var srv = form.getServiceConfiguration("SC_GetWorkshopCount");
srv.connectEvent("onCallFinished", function(success) {
  if(success) {        
        //Check to see if the applicant count for this workshop is less than 5, if it is then there is still room in the workshop
        if(form.getBO().F_WorkshopCount.getValue() <= 5) {

        //This is just a debug line where I write some output to a multi-line field
          app.getSharedData().debug(form.getBO().F_debug, form.getBO().F_tempWorkshop.getValue() + " has " + form.getBO().F_WorkshopCount.getValue() + " applicant(s).");
        } else {

         // If we get here then there is no more room in the workshop
          app.getSharedData().debug(form.getBO().F_debug, form.getBO().F_tempWorkshop.getValue() + " capacity has been exceeded.");

         //set the capExceeded field to true so that we can hide the submit button, using a rule
          form.getBO().F_CapacityExceeded.setValue("true");
          if(app.getSharedData().errString !== "") {
            app.getSharedData().errString += "<BR />";
          }
          app.getSharedData().errString += form.getBO().F_tempWorkshop.getValue() + " capacity has been exceeded."
        }
    
      app.getSharedData().currentRecord += 1;
    
    //if there are still more selections to check then clear the temporary fields, if we have reached the end of the list then we are done.
    if(app.getSharedData().currentRecord < app.getSharedData().selected_opts.length) {    

      //set the temp workshop field to the next selected workshop in the list
      form.getBO().F_tempWorkshop.setValue(get(app.getSharedData().selected_opts, app.getSharedData().currentRecord));
      form.getBO().F_WorkshopCount.setValue("");  

     //call the service again, now looking for the next selected workshop
      form.getServiceConfiguration("SC_GetWorkshopCount").callService();
    }
    

  // if the errString is not empty then that means we found a workshop that did not have space, therefore we set the checklist to invalid
    if(app.getSharedData().errString !== "") {
        form.getBO().F_WorkShopList.setValid(false, app.getSharedData().errString);
    } else {
        form.getBO().F_WorkShopList.setValid(true, "");
    }
    
    }
});


This code will continue until there are no more selected options in the list.

You might be asking..."Why can't I just use a forloop to iterate the selected options and call the service?"  The reason is that you have to provide an input to the service (the temp workshop field) and services are asynchronous which means they all run independently.  If you create a for loop then you would be calling the service several times and they would all depend on the values in the temp fields and there would be collisions.

Applying these concepts to your own application

So how do I take what was shown in this sample and apply it to my own application? Here are my thoughts:

1. Make sure you understand the overall concept.  Services are asynchronous and you have to be intentional about making sure they run in order.

2. Make sure you understand the fundamental pieces: temp fields that are used for service inputs/outputs, the service call and the service call listener. 

3. Make sure you understand what condition should terminate your loop and that it is part of your service call listener.

Deploying this Sample

1. Download the file

2. Import the application, be sure to select the deploy application and  import data check

3. Test the application!  Try checking some items and clicking the Check Workshop Availability button and submitting the form. Note that the debugging field tells you how many submissions have been received for each item you select in the list.