Loops are one of my favorite processes in programming – they allow you to step through a variable amount of data/inputs to produce a customized output! Recently while discussing an API solution with a colleague I realized just how difficult it can be to explain how to use a loop function to solve a problem, and the differences between the various loop statements.
In an attempt to help other users to navigate this topic, lets cover the key recursive functions that are supported in Salesforce SSJS.
Introduction to the FOR Loop
In my opinion the FOR Loop is best SSJS loop statement to start with – it’s the most common, practical and understandable – and shares a very similar syntax with the AMPScript FOR statement, among other programming languages. Consider the following statement and the output below:
<script runat="server">
Platform.Load("core","1");
for (i = 0; i < 10; i++) {
Write('The Count is: '+i+'<br>');
}
</script>
//Output:
The Count is: 0
The Count is: 1
The Count is: 2
The Count is: 3
The Count is: 4
The Count is: 5
The Count is: 6
The Count is: 7
The Count is: 8
The Count is: 9
The FOR statement contains 3 parts: The Initialization, Condition, and Ending Expression.
The Initialization runs a the start of the code and sets the scene. In the example above, it’s declaring that the variable “i” shall be equal to be 0.
After Initialization, the statement evaluates the expression in the Condition section. In the example above the Condition expression is “i < 10”. Is the value of “i” less than 10?
As the function just initialized and we just declared that i = 0, the expression evaluates as TRUE, and the area of code between the curly brackets “{}” is run.
After the code between the curly brackets has run, the third and last part of the statement is run, the Ending Expression. In the example above, the expression is “i++”, which is short hand for “i = i + 1” or “Add 1 to the value of i”. You can read more about JavaScript Operators here.
The value of “i” was previously 0, however this expression has incremented it by 1. Now that the Ending Expression is complete, the statement returns (loops back) to the Condition expression to be evaluated again.
“i < 10” is re-evaluated as TRUE – since “i” is now equal to 1, and “1 is less then 10” – and the code between the brackets is run again. Once complete, the statement processes the Ending Expression and increments the value of “i” by 1.
The process continues to “loop” over itself until the Condition expression evaluates as FALSE, at which time the statement concludes. In the example above, the last output was “The Count is 9” because as soon as the value of “i” reached 10, the Condition of “i < 10” was no longer true.
Practical uses for the FOR Loop
The beautiful simplicity of the FOR Loop is that it will simply run as many times as the statement requires it to. The example above used “(i = 0; i < 10; i++)” which resulted in the statement running 10 times. Having control over these values means we can make small adjustment to achieve other goals – such as counting down to 0, or counting in numbers other than 1.
Now that we understand the basics, lets use this functionality to solve a business problem.
Lets say we needed to send an email at the start of each day with a scoreboard that displays a list of employees who scored at least 100 points the previous day.
For simplicity lets also assume that the results from the previous day are saved directly into a Data Extension along with the employee names, so there is no need for any other lookups or date manipulation.
The data we have access to is as follows:
ID | Name | Points |
---|---|---|
14 | Ameen | 245 |
6 | Coby | 45 |
42 | Nolan | 25 |
38 | Trey | 77 |
62 | Lee | 112 |
79 | Duke | 145 |
24 | Conrad | 37 |
Based on the above information, we can use the following SSJS code to print a table of the employees that met the condition:
<table border=1>
<tr><th>ID</th><th>Name</th><th>Points</th></tr>
<script runat="server">
Platform.Load("core","1");
var EMP_Points = DataExtension.Init("EmployeePointsCampaign");
var filter = {Property:"EMP_Points",SimpleOperator:"greaterThanOrEqual",Value:100};
var data = EMP_Points.Rows.Retrieve(filter);
for (i = 0; i < data.length; i++) {
Write('<tr><td>'+data[i].EMP_ID+'</td><td>'+data[i].EMP_Name+'</td><td>'+data[i].EMP_Points+'</td></tr>');
}
</script>
</table>
Result:
ID | Name | Points |
---|---|---|
14 | Ameen | 245 |
62 | Lee | 112 |
79 | Duke | 145 |
There’s a lot going on in the code above – so lets break it down!
Notice that the TABLE tags are outside of the script – this is because the LOOP statement is looping over the rows (tr) inside the table for each eligible employee.
You can read more about DataExtension lookups in SSJS here, however the key things to know is that the variable of “data” now holds a JSON object which contains the payload of data returned by the retrieve function that we need to output. You can brush up on your JSON understanding with this JSON intro at W3Schools. The payload returned by the retrieve function is below:
[{"EMP_ID":14, "EMP_Name":"Ameen", "EMP_Points":245},
{"EMP_ID":62, "EMP_Name":"Lee", "EMP_Points":112},
{"EMP_ID":79, "EMP_Name":"Duke", "EMP_Points":145}]
The object contains an array of objects equal to the number of eligible employees (3); where each object has within it an array of Name/Value pairs which hold the data (EMP_ID, EMP_Name, EMP_Points).
To access the name “Ameen”, we need to reference its address in the JSON structure. In this example, its “data[0]. EMP_Name”. The first address reference is data[0] because it’s in the first object in the JSON payload and arrays start at Ordinal “0”. Next we reference the Name that the value is stored in, which is “EMP_Name”.
To reference “Duke’s” point value of 145, we would write: “data[2]. EMP_Points” .
Now that we’ve covered how to address the data, lets explore how the Loop works in this example.
Notice how the Condition statement in this Loop is “i < data.length”. The “.length” property detects how many elements are in the JSON object – which in this example is 3 – therefore the Condition statement actually resolves as “i < 3”.
As we learnt in the earlier example, the for loop will continue until the “i” is no longer less than 3; meaning “i” will step through the values starting at 0 and ending at 2: [0,1,2].
Within the Loop statement, the output line is using the Write() function to print the table elements along with the 3 values that we need; EMP_ID, EMP_Name, EMP_Points. Each of these values is prefixed with “data[i]”, meaning that as the Loop statement steps through the values [0,1,2] it will correctly address each of the 3 objects in the data payload!
The FOR IN Loop
FOR IN is another form of JavaScript Loop that uses a slightly different condition format to determine how many times to run the statement. An example of the FOR IN Loop is as follows:
<script runat="server">
Platform.Load("core","1");
var EMP_data = {"EMP_ID":14, "EMP_Name":"Ameen", "EMP_Points":245};
for (i in EMP_data) {
Write('The Value of ' +i+ ' is: ' +EMP_data[i]+ '<br>');
}
</script>
//Output:
The Value of EMP_ID is: 14
The Value of EMP_Name is: Ameen
The Value of EMP_Points is: 245
Remember above how we covered the Name/Value pairs in JSON objects? The FOR IN Loop allows you to select every “name” within an array and store it as a value; in the example above it’s stored as “i”.
With the Name attribute known, we can correctly address each Name/Value pair in the payload.
This Loop is very useful when you don’t know the name of every Name/Value pair and just need to cycle through everything that is returned. An example of this is where the Name attributes could be optional or change based on inputs. Rather than hard-coding them like we did in the first example, they can be dynamically referenced with FOR IN.
The DO WHILE Loop
The DO WHILE Loop is a slightly more complex version of the standard WHILE Loop. Since the WHILE Loop functions in much the same way as the FOR Loop , I’ll only cover the DO WHILE version.
This is the most complex Loop to learn, however the utility benefit of this loop can not be understated, it is a truly powerful function for any automation marketing team.
The DO WHILE statement comes in 2 parts – DO{} and WHILE().
<script runat="server">
Platform.Load("core","1");
var i = 0;
do {
Write("Count to " + i + "<br>");
i++;
}
while (i < 10);
</script>
//Output:
Count to 0
Count to 1
Count to 2
Count to 3
Count to 4
Count to 5
Count to 6
Count to 7
Count to 8
Count to 9
The above example is a replica of the FOR Loop we used at the top of this article, and it follows a very similar process of running a statement, the DO{} section, “while” a condition is TRUE, the WHILE() section.
This means we have direct control over when the statement ends based on values that can be evaluated as part of the statement. This can be used to interesting effect, such as running a random number generator that will output numbers until it hits the correct number:
<script runat="server">
Platform.Load("core","1");
var random = Math.floor(Math.random() * 10);
do {
Write("random is " + random + "<br>");
var random = Math.floor(Math.random() * 10);
}
while (random != 7);
</script>
//Output:
random is 4
random is 9
random is 8
random is 1
random is 3
random is 2
random is 8
random is 2
random is 9
random is 5
random is 9
random is 9
random is 8
random is 1
random is 4
random is 5
random is 0
In the above, the code will continue to run while the value of “random” is not equal to 7. In my test run it took 17 iterations before the number 7 was selected by the random number generator.
Now lets have some fun and make a function that needs to count up to a target number by adding randomly generated numbers together. It will keep generating random numbers (between 1-10) until it reaches its goal; disregarding numbers that will put it over the specified target of 100.
<script runat="server">
Platform.Load("core","1");
var target = 100;
var keepgoing = true;
var total = 0
var steps = 0
do {
var random = Math.floor(Math.random() * 10)+1;
steps++;
if ((total + random) == target) {
Write("The final Number was " + random + ", bringing to total to "+target+" on step number "+steps+"<br>");
var keepgoing = false;
} else {
if ((total + random) > target) {
Write("Number " + random + " disregarded - it would push the total to "+(total+random)+"<br>");
var keepgoing = true;
} else {
Write("Number " + random + " added - total is "+(total+random)+"<br>");
var total = (total + random);
var keepgoing = true;
}
}
}
while (keepgoing);
</script>
//Output:
Number 2 added - total is 2
Number 4 added - total is 6
Number 8 added - total is 14
Number 8 added - total is 22
Number 6 added - total is 28
Number 6 added - total is 34
Number 3 added - total is 37
Number 6 added - total is 43
Number 8 added - total is 51
Number 1 added - total is 52
Number 2 added - total is 54
Number 2 added - total is 56
Number 8 added - total is 64
Number 7 added - total is 71
Number 7 added - total is 78
Number 7 added - total is 85
Number 5 added - total is 90
Number 6 added - total is 96
Number 9 disregarded - it would push the total to 105
Number 3 added - total is 99
Number 5 disregarded - it would push the total to 104
Number 2 disregarded - it would push the total to 101
Number 7 disregarded - it would push the total to 106
Number 9 disregarded - it would push the total to 108
Number 4 disregarded - it would push the total to 103
Number 7 disregarded - it would push the total to 106
Number 2 disregarded - it would push the total to 101
Number 8 disregarded - it would push the total to 107
Number 8 disregarded - it would push the total to 107
Number 2 disregarded - it would push the total to 101
Number 2 disregarded - it would push the total to 101
Number 2 disregarded - it would push the total to 101
Number 2 disregarded - it would push the total to 101
Number 7 disregarded - it would push the total to 106
Number 9 disregarded - it would push the total to 108
Number 7 disregarded - it would push the total to 106
Number 6 disregarded - it would push the total to 105
Number 4 disregarded - it would push the total to 103
Number 6 disregarded - it would push the total to 105
The final Number was 1, bringing to total to 100 on step number 40
Practical Examples for the DO WHILE Loop
The function above was creative, but the real world applications for this kind of loop are endless!
We could write an automated email that selects items from a customer’s cart in price acceding order until it reaches the minimum spend needed for Free Shipping. Imagine getting an email from your favorite fashion retailer with the subject line “Buy these 7 items in your wishlist today and get FREE SHIPPING!”
Retailers with annual spend milestones required to maintain a loyalty status – such as Sephora, Witchery and Mimco – could use the same logic to create a personalized Call to Action for the customer to maintain membership for another year. “Hey %%fName%%, restock on these %%count%% items and maintain %%tier%% status for another year!”
The versatility of SSJS Loops is that they can be run on Cloud Pages, in Emails, and as activities in Automation Studio, so there are plenty of ways to ingest and activate your data! Be sure to ask for help on the Salesforce StackExchange if you need assistance building your SSJS Loops.