Dynamically Remove Items from List

This next example is inspired by setting up an appointment for a specific time.

Let’s say the practitioner has the following times available:

 

1 var baseTimeslots = "8-830,830-9,9-930,930-10,10-1030,1030-11,11-1130,1130-12,13-1330,1330-14,14-1430,1430-15,15-1530,1530-16";

 

I want to create a form where the user will only see the time slots that are available. As records are submitted for a specific time slot, they will be removed from the list.

To solve this use case I need to leverage Leap’s service feature, that enables one form to query another. Let’s break down the solution:

  1. When the form is submitted I create a record in a Booked Slots form (as a Service executed when the submit button is clicked), which stores the date and time slot.

    This form is critical as it will keep track of which slots are booked, but it also does not reveal any of the sensitive information. In order for any user to be able to execute the service that pulls the booked slots we have to modify the access permissions:

  2. When the user enters the date of interest, a service is called to load all the booked times for that day into a hidden dropdown. The service is configured to run in the onItemChange event of the dropdown.

     

  3. Once the service completes javaScript parses the results and sets the options into the Available Times dropdown that are not already booked. The following code is added to the onLoad event:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 app.getSharedData().convertArrayToDropdownOpts = function(theArr) { var ddopts = new Array(); for(var i=0;i<theArr.length;i++) { ddopts.push({title: get(theArr,i),value:get(theArr,i)}); } return ddopts; } app.getSharedData().optsContainValue = function(optsArr, val) { var r = false; if(typeof optsArr === "undefined" || typeof val === "undefined") { return r; } for(var o in optsArr) { var tmpOpt = get(optsArr, o); if(tmpOpt.value === val) { r = true; } } return r; } //compare the booked slots with the timeslot list var baseTimeslots = "8-830,830-9,9-930,930-10,10-1030,1030-11,11-1130,1130-12,13-1330,1330-14,14-1430,1430-15,15-1530,1530-16"; var srv_getTimes = form.getServiceConfiguration('SC_GetAvailableTimes'); srv_getTimes.connectEvent("onCallFinished", function(success) { if(success) { try { var bookedOptsDD = form.getPage("P_NewPage1").F_BookedSlots; var bookedOpts = bookedOptsDD.getOptions(); var availOptsDD = form.getPage("P_NewPage1").F_AvailableSlots ; var availTimes = new Array(); var times = baseTimeslots.split(","); for(var t in times) { var tmpT = get(times,t); if(!app.getSharedData().optsContainValue(bookedOpts, tmpT)) { availTimes.push(tmpT); } } availOptsDD.setOptions(app.getSharedData().convertArrayToDropdownOpts(availTimes)); } catch(err) { alert(err); } } });

     

The result is a dynamic form that provides feedback to the user about which times are available.

 

Note: This technique as it is here does not address simultaneous requests. Some additional code would be required to check that a slot is still available when the user clicks submit (in the situation where they opened the form and someone else submitted it before they did).

So how do we address that problem?

  1. Before the form is submitted we need to check if the time is still available. To do this we add some code to the validateButtonPressed event:

    1 2 3 4 5 6 7 //check that the time is still available if(pActionId === "S_Submit") { if(app.getSharedData().doAvilCheck === true) { form.getServiceConfiguration("SC_IsTimeAvailable").callService(); return false; } }

    If the submit button is pressed and this newly added global variable is set to true, then call the service, otherwise let the submit complete.

  2. In the onLoad event I set the global variable:

    1 app.getSharedData().doAvilCheck = true;
  3. In the onLoad event I added an onCallFinished handler for the service that checks if the time is still available:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var srv_isTimeAvail = form.getServiceConfiguration("SC_IsTimeAvailable"); srv_isTimeAvail.connectEvent("onCallFinished", function(success) { if(success) { var isBooked = BO.F_TimeslotBooked.getValue(); if(!isBooked) { //submit app.getSharedData().doAvilCheck = false; BO.F_AvailableSlots.setValid(true, ""); //trigger submit app.getSharedData().triggerButton("S_Submit"); } else { BO.F_AvailableSlots.setValid(false, "Time is no longer available. Someone scooped it from under your nose!"); BO.F_AvailableSlots.setValue(""); form.getServiceConfiguration("SC_GetAvailableTimes").callService(); } } });
  4. In the onLoad event I added a new function for triggering the submit button:

    1 2 3 4 5 6 7 app.getSharedData().triggerButton = function(btnID) { var actionButtons = form.getStageActions(); for(var i=0; i<actionButtons.length; i++){ if(get(actionButtons, i).getId() === btnID) get(actionButtons, i).activate(); } }

Now our solution is more robust and can handle simultaneous users.

The sample is attached, try it out!