Data privacy notice

 

When this content is loaded, usage information is transmitted to Vimeo and may be processed there.

 

             

Workflow flow control: Loops

Modified on Wed, 31 Jul at 8:05 AM

Available starting with version 8.2.0


Contents


Loops are an advanced flow control element that allow you to run a set of actions multiple times, possibly with different data. For example, if your form contains a repeated input field for emails, you could send an email once for each entered email.


formcycle provides three different kind of loops. A basic loop and two advanced loops:

  • For-each loop: Lets you iterate over a pre-defined list of items, such as repeated form elements or a comma separated values.
  • Do-until and while loop: Lets you manually decide when to stop the loop via a condition.


See further down for a detailed description of these different loop types. Several noteworthy points regarding loops in general are outlined below.


Placeholder variables


As you might know, you can use placeholder variables such as [%$sql_statement.RESULT] to access the values provided by a workflow action named sql_statement. Such result placeholders are available after an action was executed successfully. 


Loops also provide a result, which contains the number of times the loop was run. However, loops additionally also provide data while the loop (and the actions it contains) are being run.Use [%$loop_name.CURRENT%] to access this data.


All loops let you access the index of the current loop iterator via [%$loop_name.CURRENT.index%] (0 for the first iteration, 1 for the second iteration, etc.). Some loops such as the for-each loop also let you access the data of the current element via

[%$loop_name.CURRENT.item%]


Files from previous actions


Most workflow actions that let you select files (such as File download) also let you choose a previous action that creates files (such as Fill PDF) as the file source. When used within a loop, you need to distinguish between two different cases, depending on the relative location of the two actions:


  • Both the action providing the files and the action consuming the files are within the same loop: Only the file from the current loop iteration will be used.

    For example, you can put a Fill Word action followed by an Email action in the same loop and select the generated Word document as an attachment for the email. Then, for each loop iteration, a Word document will be generated and attached to the sent email.

  • The action consuming the file is outside the loop that contains the action providing the files: All files generated by the action will be used.

    For example, you can iterate over a repeated fieldset and use a Fill Word action inside a loop to generate a Word document with the form data submitted for each fieldset repetition. Then, you can place a File download action after the loop and select the Fill word action as the file source. This will create a download with all Word documents from all loop iterations.


Stop loop iterations manually


The most common use case is the for-each loop, which iterates over a predefined list of items. Usually, you will want to let that loop run to completion and not stop it manually. For the while and do-until loop, as well as some advanced use cases for the for-each loop, you might want to gain more control over when and how to stop or skip loop iterations. formcycle provided two workflow actions that let you achieve this:


  • Break -- When a break action gets executed, it stops the current loop completely and jumps to the end of the loop. All further iterations are skipped.
  • Continue -- When a continue actions gets executed, it skips the current loop iteration, jumps back to the beginning of the loop and continues with the next loop iteration.


You can use these actions directly within a loop, but usually, you will want to stop or skip a loop only when a certain condition is fulfilled. You can use flow control actions such as Switch or Condition and put the break or continue action within one of the flow control's branches to achieve this.


These two actions must be placed inside a loop, or a validation error will be raised when you attempt to save the workflow. 


By default, the closest loop that contains the break or continue action is stopped or skipped. Optionally, both actions allow you to select a loop target. If you have nested loops, with one loop inside another loop, you can use this feature to stop or skip the outer loop from within the inner loop.


Hover over the the break or continue action with the mouse to highlight the loop target that this action affects.


Limitations


  • Loops can be nested (putting a loop inside another loop) without limits.
  • The total number of actions that can be run during a workflow execution is limited by formcycle. This limit is a configurable system-wide setting that (currently) defaults to 2000. Loops are affected by this limit as well.When too many actions are executed as the result of a loop, formcycle will abort the workflow. This is a safety measure to prevent endless loops. If you use the for-each loop, you usually need not worry about this issue, as that type of loop makes it impossible to create endless loops. If you use the advanced while or do-until loops and hit the action limit, you may need to verify that your loop has a well-defined end.


Loop types


For-each loop


The for-each loop lets you choose a source with a list of items and runs the the actions inside the loop once for each item.


For-each loops are the most common type of loops and should be used when possible. Only consider the advanced types of loops described below when a for-each loop does not meet your needs. The two main advantages of the for-each loop over the advanced loops are:

  • Ease of use -- You simply select the items you wish to iterate over. The current item is available during each run of the loop, without the need to access that item with custom expressions, scripts, or plugins. 
  • Well-defined end -- Once the last item was reached, the for-each loop stops. Advanced loops require that you define a custom condition for when to stop the loop. Accidental mistakes in this condition may result in the loop running forever, consuming resources, preventing other workflows from running, and increasing the time it takes to submit a form.

The following item sources are available currently:


(common)


Repeated form field
Select a form field, container, or fieldset that was marked as repeated in the form designer. You can also select a form field inside a repeated container. The loop then iterates over each existing repetition.

During the loop, the current item can be accessed via the placeholder variable [%$loop_name.CURRENT.item.values%]. It contains the values of all items within that repetition. For example, when you iterate over the repeated fieldset named fsPersonalData and that fieldset contains the input fields tfFirstName and tfLastName, then [%$loop_name.CURRENT.item.values.tfFirstName%] and [%$loop_name.CURRENT.item.values.tfFirstName%] point to the current value for the first and last name, respectively.

In addition, when you use this kind of loop, all references to form fields will resolve to the value of the current repetition. Continuing the example above, the form placeholder [%tfFirstName%] yields the first name of the current repetition when used in an action inside the loop.

For example, the HTTP request provides an option that lets you include the values of a form fields in the request. Looping over repeated form fields also affects such actions: within the loop, only the values of the current repetition are included in the HTTP request. This also applies to the Change form values action: only the values of the current repetition are changed when used within a loop.


Form field values
Select a form field that can have multiple values, such as a checkbox select field. The loop then iterates over each value.

During the loop, the current item can be accessed via the placeholder variable [%$loop_name.CURRENT.item.values%]. It contains all values for the current index from all existing repetitions. If the element is not repeated, there will be only one value which you can access via [%$loop_name.CURRENT.item.values[0]%]

For example, assume you have a checkbox select field named selHobbies with the following options
  • value: 1, display name: Reading
  • value: 2, display name: Swimming
  • value: 3, display name: Hiking


When the user select the hobbies Reading and Hiking, looping over the values of selHobbies results in 2 iterations. The first time, the placeholder variable [%$loop_name.CURRENT.item.values[0]%] evaluates to "1", the second time it evaluates to "3".


In case the form field selHobbies was marked as a repeated field and the user creates 3 repetitions with following values:

  • repetition 1: Reading, Hiking
  • repetition 2: Swimming
  • repetition 3: Reading, Swimming, Hiking


Then the loop runs the child actions 3 times, with the following values:

  • iteration 1
    • [%$loop_name.CURRENT.item.values[0]%] is "1" (Reading, 1st value of the 1st repetition)
    • [%$loop_name.CURRENT.item.values[1]%] is "2" (Swimming, 1st value of the 2nd repetition)
    • [%$loop_name.CURRENT.item.values[2]%] is "1" (Reading, 1st value of the 3rd repetition)
  • iteration 2
    • [%$loop_name.CURRENT.item.values[0]%] is "3" (Hiking, 2nd value of the 1st repetition)
    • [%$loop_name.CURRENT.item.values[1]%] is "" (empty, 2nd repetition does not have a 2nd value)
    • [%$loop_name.CURRENT.item.values[2]%] is "2" (Swimming, 2nd value of the 3rd repetition)
  • iteration 3
    • [%$loop_name.CURRENT.item.values[0]%] is "" (empty, 1st repetition does not have 3rd value)
    • [%$loop_name.CURRENT.item.values[1]%] is "" (empty, 2nd repetition does not have a 3rd value)
    • [%$loop_name.CURRENT.item.values[2]%] is "3" (Hiking, 3rd value of the 3rd repetition)


You can also combine this item source with the repeated form field item source: Create a loop over the repetition of selHobbies. Then, inside that loop, create a nested loop over the values of selHobies. This lets you access each value for each repetition individually and perform some other workflow actions. In the example above, the outer loop would iterate 3 times, once for each repetition. The inner loop over the field values would iterate a variable number of times, depending on the number of selected options for that repetition (2 for the first repetition, 1 for the second repetition, 3 for the third repetition). In total the child actions would be executed 6 times. 


In addition, when you use this kind of loop, all references to form fields will resolve to the value at the current index. Continuing the example above, when the form field is not repeated and the user selects the hobbies Reading and Hiking, the loop run the child actions 2 times. The first time, the form placeholder [%selHobbies%] evaluates to "1", the second time it evaluates to "3". You can also use form functions to access the display name of the option: [%selHobbies.lsttxt()%] yields "Reading" the first time, and "Hiking" the second time.


Character separated values
Enter a list of values, separated by a character of your choice. The values are split at the configured separator, and the loop then iterates over each value. During the iteration, the placeholder variable [%$loop_name.CURRENT.item%] refers to the current column.

Usually you'll want to use a placeholder variable that contains a list of values that need to be split. By default, values are split on commas, but there are several options that let you customize how values are split. At the top, you can find a list of example values that illustrates how the values need to be formatted in order to be split properly. The following options are available:
  • Delimiter -- The character that limits the values, such as a comma (,) or semicolon (;).
  • Treat control characters and line breaks as delimiter -- When enabled, line breaks and other control characters are treated as a separator between values. When disabled, line breaks and control characters are included in the value.
  • Opening / closing quote character -- Characters that can be used to quote a value that contains special characters, such as a single (') or double (") quote character. You can also use different opening and closing characters, such as when you have values quoted by angle brackets, such as <Item 1>, <Item 2>, <Item 3>
  • Quote character twice inserts literal quote character -- When enabled, a repeated quote character inside a quoted value is treated as a literal quote character. For example: "Juliet said: ""I love you""." When disabled, the first quote character is treated as the end of the quote, and the next quote character as the start of a new quote.
  • Escape character -- The character that can be used to escape special characters within a quoted value, such as a backslash (\). The example above could also be written as "Juliet said: \"I love you\"." 
  • Remove spaces from the beginning and end of each value -- When enabled, spaces are removed from the beginning and end of each value.
  • Remove empty values -- When enabled,  empty values are omitted. Can be used in combination with the above option to omit values that consist only of spaces.

Rows of character separated values
Similar to the above (character separated values), but lets you iterate over multiple rows, where each row consist of multiple columns that are separated by a certain separator character. You can use this type, for example, to iterate over a CSV file. During the iteration, the placeholder variable [%$Loop.CURRENT.item%] refers to the current row.


As with character separated values, you can use a placeholder variable that contains a list of rows that need to be split. In addition, this type also lets you select a file directly, such as a form or client CSV file.

By default, values are split on commas, but there are several options that let you customize how values are split. At the top, you can find a list of example values that illustrates how the rows need to be formatted in order to be split properly. The available options are similar to the type above:
  • Treat first line as header -- When enabled, the first line (first row) is treated as a header and not included in the rows. The value of each cell of the first line gets used as the name for that column. For example, if the header contains the three values ID, name, and email; then you can use the placeholder variables [%$loop_name.CURRENT.item.ID%], [%$loop_name.CURRENT.item.name%], and [%$loop_name.CURRENT.item.email%] to refer to the first, second, and third column during the iteration. When this option is disabled, you can use the index of the column as its name, e.g. [%$loop_name.CURRENT.item.0%] or [%$loop_name.CURRENT.item.1]%].
  • Delimiter -- The character that limits the values, such as a comma (,) or semicolon (;).
  • Treat control characters and line breaks as delimiter -- When enabled, line breaks and other control characters are treated as a separator between values. When disabled, line breaks and control characters are included in the value.
  • Opening / closing quote character -- Characters that can be used to quote a value that contains special characters, such as a single (') or double (") quote character. You can also use different opening and closing characters, such as when you have values quoted by angle brackets, such as <Item 1>, <Item 2>, <Item 3>
  • Quote character twice inserts literal quote character -- When enabled, a repeated quote character inside a quoted value is treated as a literal quote character. For example: "Juliet said: ""I love you""." When disabled, the first quote character is treated as the end of the quote, and the next quote character as the start of a new quote.
  • Escape character -- The character that can be used to escape special characters within a quoted value, such as a backslash (\). The example above could also be written as "Juliet said: \"I love you\"." 
  • Remove spaces from the beginning and end of each value -- When enabled, spaces are removed from the beginning and end of each value.
  • Remove empty values -- When enabled,  empty values are omitted. Can be used in combination with the above option to omit values that consist only of spaces.
  • Remove blank linkes -- When enabled, blank lines are omitted. Blank lines are lines that consist of only whitespace, without any separator characters.
  • Line breaks -- Lets you configure which kind of line breaks should be recognized. If you are unsure, simply leave all options enabled.


JSON value (workflow action result)
Enter a string that represents valid JSON value. The loop then iterates over each item of that JSON value. Leading and trailing spaces in the string are ignored.

One common use case are workflow action results. All workflow actions return their result as a JSON value. For example, the Database statement action lets you run an SQL query to retrieve data from a database. It returns a list of rows with the obtained data. To iterate over each result row, you can use a for-each loop with a JSON data source and enter the placeholder variable [%$sql_statement.RESULT.rows$%] as the JSON value.

The exact behavior depends on the type of the JSON value:

  • JSON object -- Iterates over each entry in the object. [%$loop_name.CURRENT.key%] points to the name of the current property, [%$loop_name.CURRENT.item%] to its value.
  • JSON array -- Iterates over each item in the array. [%$loop_name.CURRENT.item%] points the current item.
  • JSON primitives (null, boolean, number, string) -- Performs a single loop iteration with that primitive as the value of [%$loop_name.CURRENT.item%]. This is provided for consistency, but note that you should usually iterate either over an object or an array.
  • Invalid JSON -- No iteration is performed and a soft error (warning) is logged. 

List of files
Select one or more files. The loop then iterates over each file. Within the loop, you can select the loop action as a file source.

This is useful especially for actions that only allow a single file. For example, you could select a list of PDF files to iterate over, then place a Fill PDF action inside the loop and select the loop as the PDF document to fill. This way, you can fill each PDF document with values. This would not be possible otherwise, as the Fill PDF action only allows for a single file to be selected.

(advanced)


List of attachments

Select one or more attachments. The loop then iterates over each attachment. Within the loop, you can select the loop action as a file source.

This is an advanced item source. Most actions usually just require any file to be selected, irrespective of the file's origin. Some specialized actions require a (form record) attachment to be selected. Such actions can be combined with this item source to execute them once for each attachment from a list of attachments.

While / Do-until loop


The while and do-until loop are advanced loops, sometimes also called manual loops.


These loops let you define a custom condition. The loop is then run for as long as the condition is fulfilled. It stops only once the condition evaluates to false. While this renders manual loops quite versatile, it comes at the cost of risking potentially endless loops when misconfigured. We recommend that you prefer a for-each loop when possible and only resort to manual loops when absolutely required. Please note that to prevent system overload, formcycle enforces an upper limit on the number of actions that can be executed during a single workflow execution. When that limit is reached, the workflow is aborted with a failure.


As a precondition for loops that do not run forever, you must setup a condition whose outcome can change between different loop iterations. For example, you could use a placeholder variable referencing the current value of a counter; and increment that counter within the loop. Alternatively, you could also use a tautology as the condition (=always evaluates to true) and put a condition or switch within the loop that contains a break action, which then ends the loop.


Two types of manual loops are available:

  • While loop -- The condition is at the top of the loop. When the loop is run, it starts by checking the condition. When the condition is not fulfilled the first time, the actions within are never run. Corresponds to the while loop statement in programming ( while (condition) statement )
  • Do-until loop -- The condition is at the bottom of the loop. When the loop is run, it starts by executing the actions within the loop. The condition is checked only at the end. In contrast with the while loop, the actions within the loop are always run at least once. Corresponds to the do-while loop statement in programming ( do statement while (condition) ).

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article