Search code examples
coldfusioncoldfusion-10cfmlcoldfusion-11lucee

How do I accomplish nesting a loop iteration in a variable inside a loop in CFML


I am trying to loops through a json response in CFML, and need to do one call to get the number of pages, then a call for each successive page, then loop through items to get my data. In doing so I have a nested loop that requires a nested variable. So, for example, my initial loop will result in:

#jsonarray.items.1.id#
#jsonarray.items.2.id#
#jsonarray.items.3.id#
#jsonarray.items.4.id#
and so on.

So in my inside loop, I am trying to replace that number by doing another loop like this:

  <cfloop from="1" to="50" index="thisBatchItem">
  </cfloop> 

But then, I would have to nest the index inside my variable, and that of course does not work.

Can someone point to what I am missing here?

Here is the code I am working with, and you will see the obvious places where I have the problem. I put in #jsonarray.items.#thisBatchItem#.id# just to show where I am trying to make this happen. I know it does not work.

<cfhttp method="GET" result="httpResp" url="https://example.com/api?filter[batch.date][gte]=2022-02-01&filter[batch.date][lte]=2022-03-07&page=1&per-page=50" throwonerror="false">
    <cfhttpparam type="header" name="Authorization" value="Bearer XXXXXXXXXXXXXXXXXXXXXXXXXX">
    <cfhttpparam type="header" name="Content-type" value="application/json">
</cfhttp>            

<cfoutput>
    <cfloop from="1" to="#pageCount#" index="thisPage">

        <cfhttp method="GET" result="httpResp" url="https://example.com/api?filter[batch.date][gte]=2022-02-01&filter[batch.date][lte]=2022-03-07&page=#thisPage#&per-page=50" throwonerror="false">
            <cfhttpparam type="header" name="Authorization" value="Bearer XXXXXXXXXXXXXXXXXXXXXXXXXX">
            <cfhttpparam type="header" name="Content-type" value="application/json">
        </cfhttp>            
        <cfset jsonarray = deserializeJson(httpResp.fileContent)>
        <cfloop from="1" to="50" index="thisBatchItem">
            <cfif StructKeyExists(jsonarray,"#jsonarray.items.#thisBatchItem#.id#")>
                #jsonarray.items.[#thisBatchItem#].id#<br>
            </cfif>
        </cfloop>
    </cfloop>
</cfoutput>

Solution

  • Since items is an array of structures, it's simpler and cleaner to use an "array" loop.

    If some of the structure keys are optional, try using the safe navigation operator ?.. In the example below, it prevents an error from occurring when the code uses a non-existent key name like "lookMaNoErrors"?

    <cfset jsonResponse = deserializeJson(httpResp.fileContent)>
    <cfloop array="#jsonResponse.items#" index="currentItem">
        id #currentItem.id#<br> 
        lookMaNoErrors #currentItem?.lookMaNoErrors#<br>
    </cfloop>
    

    Update:

    To answer the original question, you need to use structure notation. Also, instead of hard coding the upper limit of the loop, use the array length instead:

    <cfloop from="1" to="#arrayLen(jsonResponse.items)#" index="itemIndex">
        id #jsonResponse.items[itemIndex].id#            
        
    </cfloop>
    

    demo trycf.com