Iterate Elements in an Array to Create HTML Tables from a For Loop in Arcade

21204
2
Jump to solution
03-08-2022 09:11 PM
PeterDalrymple
Regular Contributor

Hi all,

I'm a bit stuck trying to generate multiple HTML tables (or conditionally visible table rows) in a popup based upon the value of fields in an array. In this case, multiple tests are being performed (up to five) on one meter, but I only want to show results tables for tests that were actually performed so that I don't have blank table rows and/or use more real estate than necessary. The data is flat, so there are redundant fields (as you can see in the global variables) rather than a one-to-many relationship. There is one Boolean field (ADD_TEST_#) that is flipped from "No" to "Yes" before each test is performed. Each has a default value of "No". The code below works great for the first test, but fails to create any additional tables in the popup for additional test. I realize the code could be optimized, but I don't want to spend too much more time on this until I know this is achievable.

var myList = [$feature.ADD_TEST_1, $feature.ADD_TEST_2, $feature.ADD_TEST_3, $feature.ADD_TEST_4, $feature.ADD_TEST_5]
var field1 = [IIF(IsEmpty($feature.T1_VOL_MIN), "No Value", $feature.T1_VOL_MIN), IIF(IsEmpty($feature.T2_VOL_MIN), "No Value", $feature.T2_VOL_MIN), IIF(IsEmpty($feature.T3_VOL_MIN), "No Value", $feature.T3_VOL_MIN), IIF(IsEmpty($feature.T4_VOL_MIN), "No Value", $feature.T4_VOL_MIN), IIF(IsEmpty($feature.T5_VOL_MIN), "No Value", $feature.T5_VOL_MIN)] 
var field2 = [IIF(IsEmpty($feature.T1_TVOL_FLWD), "No Value", $feature.T1_TVOL_FLWD), IIF(IsEmpty($feature.T2_TVOL_FLWD), "No Value", $feature.T2_TVOL_FLWD), IIF(IsEmpty($feature.T3_TVOL_FLWD), "No Value", $feature.T3_TVOL_FLWD), IIF(IsEmpty($feature.T4_TVOL_FLWD), "No Value", $feature.T4_TVOL_FLWD), IIF(IsEmpty($feature.T5_TVOL_FLWD), "No Value", $feature.T5_TVOL_FLWD)]
var field3 = [IIF(IsEmpty($feature.T1_ACCURCY), "No Value", $feature.T1_ACCURCY), IIF(IsEmpty($feature.T2_ACCURCY), "No Value",$feature.T2_ACCURCY), IIF(IsEmpty($feature.T3_ACCURCY), "No Value", $feature.T3_ACCURCY), IIF(IsEmpty($feature.T4_ACCURCY), "No Value", $feature.T4_ACCURCY), IIF(IsEmpty($feature.T5_ACCURCY), "No Value", $feature.T5_ACCURCY)]

for (var v in myList){
    if(myList[v] == "Yes"){
        var testNum = (v + 1)
        var i = v
        var firstField = field1[i]
        var secondField = field2[i]
        var thirdField = field3[i]
        var myTable = { 
        	"type" : "text", 
        	"text" : `
            <table style="width:80%">
              <tbody>
                <tr style="background-color:#636363;color:#FFFFFF;font-size:16px;text-align:center;">
                  <td colspan="2">
                    <span style="font-size:16px;">
                      <strong>Test ${testNum} Results</strong></span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Volume Min</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${firstField}</span>
                  </td>
                </tr>
                <tr style="background-color:#d9d9d9;">
                  <td>
                    <span style="font-size:14px;">
                      <strong>Total Volume Flowed</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${secondField}</span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Accuracy (%)</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${thirdField}</span>
                  </td>
                </tr>
              </tbody>
            </table>
        `
    }
    return myTable
        
    }else{
        return "No results for Test " + (v + 1)
    }
    
}

 

@XanderBakker @PaulBarker, any thoughts on what may be causing the issue?

Thanks in advance!

Peter

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

You return inside the for loop, not outside.

When you return from a function, you stop executing it at that point. Everything after it will not be evaulated:

function test() {
    var x = 2
    return x // returns 2
    // everything after this will never get executed.
    // the new value of x will never be returned, x won't even get changed at all.
    x += 5
    return x
}

 

So when you return inside a for loop, you return just the first element:

var arr = [25, 30, 103]
for(var i in arr) {
    return arr[i] + 1  // this will just return 26 and then stop
}

 

What you want to do is this:

  • Create an object before the loop that will hold all the intermediate results. In most cases, this will be an array or a string.
  • Inside the loop, append your intermediate results to that object.
  • After the loop, return that object.
var arr = [25, 30, 103]
var output_arr = []
for(var i in arr) {
    Push(output_arr, arr[i] + 1)  // append the intermediate result
}
return output_arr  // this will return [26, 31, 104]

 

All in all you just have to restructure your code a bit:

var myList = ["Yes", "Yes", "No", "No", "Yes"]
var field1 = [1, 1, "N/A", "N/A", 1] 
var field2 = [1, 1, "N/A", "N/A", 1] 
var field3 = [1, 1, "N/A", "N/A", 1] 

var myHTML = ""  // this string will hold all the tables

for (var v in myList){
    if(myList[v] == "Yes"){
        var testNum = (v + 1)
        var i = v
        var firstField = field1[i]
        var secondField = field2[i]
        var thirdField = field3[i]
        // append the table html. Note that this isn't a dict anymore!
        myHTML += `
            <table style="width:80%">
              <tbody>
                <tr style="background-color:#636363;color:#FFFFFF;font-size:16px;text-align:center;">
                  <td colspan="2">
                    <span style="font-size:16px;">
                      <strong>Test ${testNum} Results</strong></span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Volume Min</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${firstField}</span>
                  </td>
                </tr>
                <tr style="background-color:#d9d9d9;">
                  <td>
                    <span style="font-size:14px;">
                      <strong>Total Volume Flowed</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${secondField}</span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Accuracy (%)</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${thirdField}</span>
                  </td>
                </tr>
              </tbody>
            </table>
        `
    } else {
        myHTML += "<p>No results for Test " + (v + 1) + "</p>"
    }
}
// return the complete HTML outside of the for loop
return {"type": "text", "text": myHTML}

Have a great day!
Johannes

View solution in original post

2 Replies
JohannesLindner
MVP Frequent Contributor

You return inside the for loop, not outside.

When you return from a function, you stop executing it at that point. Everything after it will not be evaulated:

function test() {
    var x = 2
    return x // returns 2
    // everything after this will never get executed.
    // the new value of x will never be returned, x won't even get changed at all.
    x += 5
    return x
}

 

So when you return inside a for loop, you return just the first element:

var arr = [25, 30, 103]
for(var i in arr) {
    return arr[i] + 1  // this will just return 26 and then stop
}

 

What you want to do is this:

  • Create an object before the loop that will hold all the intermediate results. In most cases, this will be an array or a string.
  • Inside the loop, append your intermediate results to that object.
  • After the loop, return that object.
var arr = [25, 30, 103]
var output_arr = []
for(var i in arr) {
    Push(output_arr, arr[i] + 1)  // append the intermediate result
}
return output_arr  // this will return [26, 31, 104]

 

All in all you just have to restructure your code a bit:

var myList = ["Yes", "Yes", "No", "No", "Yes"]
var field1 = [1, 1, "N/A", "N/A", 1] 
var field2 = [1, 1, "N/A", "N/A", 1] 
var field3 = [1, 1, "N/A", "N/A", 1] 

var myHTML = ""  // this string will hold all the tables

for (var v in myList){
    if(myList[v] == "Yes"){
        var testNum = (v + 1)
        var i = v
        var firstField = field1[i]
        var secondField = field2[i]
        var thirdField = field3[i]
        // append the table html. Note that this isn't a dict anymore!
        myHTML += `
            <table style="width:80%">
              <tbody>
                <tr style="background-color:#636363;color:#FFFFFF;font-size:16px;text-align:center;">
                  <td colspan="2">
                    <span style="font-size:16px;">
                      <strong>Test ${testNum} Results</strong></span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Volume Min</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${firstField}</span>
                  </td>
                </tr>
                <tr style="background-color:#d9d9d9;">
                  <td>
                    <span style="font-size:14px;">
                      <strong>Total Volume Flowed</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${secondField}</span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Accuracy (%)</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${thirdField}</span>
                  </td>
                </tr>
              </tbody>
            </table>
        `
    } else {
        myHTML += "<p>No results for Test " + (v + 1) + "</p>"
    }
}
// return the complete HTML outside of the for loop
return {"type": "text", "text": myHTML}

Have a great day!
Johannes
PeterDalrymple
Regular Contributor

Hi Johannes, thanks so much for your help! That did fix the issue I was having. Here is the working code for anyone else's benefit.

 

 

var myList = [$feature.ADD_TEST_1, $feature.ADD_TEST_2, $feature.ADD_TEST_3, $feature.ADD_TEST_4, $feature.ADD_TEST_5]
var field1 = [IIF(IsEmpty($feature.T1_VOL_MIN), "No Value", $feature.T1_VOL_MIN), IIF(IsEmpty($feature.T2_VOL_MIN), "No Value", $feature.T2_VOL_MIN), IIF(IsEmpty($feature.T3_VOL_MIN), "No Value", $feature.T3_VOL_MIN), IIF(IsEmpty($feature.T4_VOL_MIN), "No Value", $feature.T4_VOL_MIN), IIF(IsEmpty($feature.T5_VOL_MIN), "No Value", $feature.T5_VOL_MIN)] 
var field2 = [IIF(IsEmpty($feature.T1_TVOL_FLWD), "No Value", $feature.T1_TVOL_FLWD), IIF(IsEmpty($feature.T2_TVOL_FLWD), "No Value", $feature.T2_TVOL_FLWD), IIF(IsEmpty($feature.T3_TVOL_FLWD), "No Value", $feature.T3_TVOL_FLWD), IIF(IsEmpty($feature.T4_TVOL_FLWD), "No Value", $feature.T4_TVOL_FLWD), IIF(IsEmpty($feature.T5_TVOL_FLWD), "No Value", $feature.T5_TVOL_FLWD)]
var field3 = [IIF(IsEmpty($feature.T1_ACCURCY), "No Value", $feature.T1_ACCURCY), IIF(IsEmpty($feature.T2_ACCURCY), "No Value",$feature.T2_ACCURCY), IIF(IsEmpty($feature.T3_ACCURCY), "No Value", $feature.T3_ACCURCY), IIF(IsEmpty($feature.T4_ACCURCY), "No Value", $feature.T4_ACCURCY), IIF(IsEmpty($feature.T5_ACCURCY), "No Value", $feature.T5_ACCURCY)]
var myTable = ""

for (var v in myList){
    if(myList[v] == "Yes"){
        var testNum = (v + 1)
        var i = v
        var firstField = field1[i]
        var secondField = field2[i]
        var thirdField = field3[i]
        myTable += 
            `<table style="width:82%">
              <tbody>
                <tr style="background-color:#636363;color:#FFFFFF;font-size:16px;text-align:center;">
                  <td colspan="2">
                    <span style="font-size:16px;">
                      <strong>Test ${testNum} Results</strong></span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Volume Min</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${firstField}</span>
                  </td>
                </tr>
                <tr style="background-color:#d9d9d9;">
                  <td>
                    <span style="font-size:14px;">
                      <strong>Total Volume Flowed</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${secondField}</span>
                  </td>
                </tr>
                <tr>
                  <td>
                    <span style="font-size:14px;">
                      <strong>Accuracy (%)</strong></span>
                  </td>
                  <td>
                    <span style="font-size:14px;">${thirdField}</span>
                  </td>
                </tr>
              </tbody>
            </table>`
    }else if (myList[v] == "No") {
        var testNum = (v + 1)
        mytable += 
        `<table style="width:82%">
            <tbody>
                <tr style="background-color:#FFC107;color:#FFFFFF;font-size:16px;text-align:center;">
                  <td colspan="2">
                    <span style="font-size:16px;">
                      <strong>No results for Test ${testNum}</strong></span>
                  </td>
            </tbody>
        </table>`
    }
}

return {"type" : "text", "text" : myTable}

 

Cheers,

Peter

0 Kudos