Coldfusion/Lucee 多个条件 select 通过 AJAX

Coldfusion/Lucee multiple conditional select via AJAX

我目前正在自学(再自学)JavaScript 和 jQuery 以重写在 Lucee 上运行的遗留应用程序。

部分重写需要对基本功能进行多项添加。一个具体的添加是将“街道名称”select 字段添加到现有的“县名”->“城市名称”select 字段。

我发现了这个 Whosebug 问题:Coldfusion conditional select option does not work in IE9, Chrome and Firefox

使用该问题的基础;我写了以下内容:

<!--- county.cfm --->
<cfif structKeyExists(url,'work_area_county_id')>
    <cfset loadState() />
</cfif>

<cfif structKeyExists(url,'work_area_city_id')>
    <cfset loadStreet() />
</cfif>

<cfset loadCounty() />

<cffunction name="loadCounty">
    <cfquery name="qCounty">
        SELECT work_area_county_id, work_area_county_name FROM work_area_county
    </cfquery>
</cffunction>   

<cffunction name="loadState">
    <cfset variables.work_area_county_id = url.work_area_county_id />
    <cfquery name="qCity">
        SELECT work_area_city_id, work_area_city_name, work_area_county_id FROM work_area_city WHERE work_area_county_id = <cfqueryparam value="#variables.work_area_county_id#" cfsqltype="cf_sql_int">
    </cfquery>
    <cfoutput>
        <select name="state" class="form-control">
            <option value="">Select City</option>
            <cfloop query="qCity">
                <option value="#work_area_city_id#">#work_area_city_name#</option>
            </cfloop>
        </select>
    </cfoutput>
</cffunction>

<cffunction name="loadStreet">
    <cfset variables.work_area_city_id = url.work_area_city_id />
    <cfquery name="qStreet">
        SELECT work_area_street_id, work_area_street_name, work_area_city_id FROM work_area_street WHERE work_area_city_id = <cfqueryparam value="#variables.work_area_city_id#" cfsqltype="cf_sql_int">
    </cfquery>
    <cfoutput>
        <select name="state" class="form-control">
            <option value="">Select Street</option>
            <cfloop query="qStreet">
                <option value="#work_area_street_id#">#work_area_street_name#</option>
            </cfloop>
        </select>
    </cfoutput>
</cffunction>
<!--- display.cfm --->
<cfinclude template="includes/county.cfm">

<cfoutput>
    <form name="state_populate">
        <select name="county" id="county">
            <option value="0">Select</option>
            <cfloop query="qCounty">
                <option value="#work_area_county_id#">
                    #work_area_county_name#
                </option>
            </cfloop>
        </select>
        <div id="city">
            <select name="city" class="form-control">
                <option value="">Select</option>
             </select>
        </div>
        <div id="street">
            <select name="street" class="form-control">
                <option value="">Select</option>
             </select>
        </div>
    </form>
</cfoutput>
// The JS

$('#county').change(function() {
    var value = $('#county').val();
    $.ajax({
        type: "get",
        url:'includes/county.cfm?work_area_county_id='+value,
        success: function(response) {
            $('#city').html(response);
        },
        error: function(jqXHR, status, error) {
            console.log(status + ": " + error);
        }
    });
});

上面的代码在 selecting "County Name" 时运行良好。它在第二个 select 字段中正确显示“城市名称”。然后我尝试在第三个 select 字段中添加“街道名称”并添加我“认为”应该适用于 CFML 和 HTML 的内容。当我到达代码的 JS 部分时,我撞到了砖墙。我似乎找不到,也许是因为缺少正确的搜索词,如何添加额外的 AJAX 调用。

我发现了这个问题:Parallel asynchronous Ajax requests using jQuery

有多个答案,但我“认为”与我的问题相关的最接近的答案是:

$.whenAll({
    val1: $.getJSON('/values/1'),
    val2: $.getJSON('/values/2')
})
    .done(function (results) {
        var sum = results.val1.value + results.val2.value;

        $('#mynode').html(sum);
    });

我相信他们被称为“承诺”?

代码需要防止第二个 select 字段“城市名称”发生变化,并正确使用具有多个值的 AJAX“url”参数。我知道参考上面的代码,URL 部分可能需要与此“类似”的东西:

url:'includes/county.cfm?work_area_county_id='+ value + '&work_area_city_id=' + value

供考虑:

  1. 我知道我的代码不是很好而且我知道它可以写得更好。我正在努力改进。
  2. 我不是全职编码员,但我断断续续地编码多年。我仍然认为自己是 CFML/JavaScript/jQuery 的新手,所以很多方法都让我头疼。
  3. 代码会用cfscript写,以后转成CFC。现在我让它变得简单并使用了标签。
  4. 我从 display.cfm.
  5. 中删除了不相关的 HTML 代码

如有任何意见或指导,我们将不胜感激! :D

我将向您展示我将如何处理此类任务的示例。我的回答可能不是最好或最干净的解决方案:我过去的编码实践很糟糕(我仍然倾向于写意大利面条,而且我一直在努力反对这样做)。但是,我正在改变那些坏习惯,这很有趣。

我的解决方案是用 OOP 方法编写的。我真的建议每个人都尝试走这条路,因为很快就会开始感觉更自然:感觉不错,尤其是当您需要修复或扩展代码时。

那时我也会尝试使用 cfscript 而不是标签,因为使用组件和函数编写 OOP 更简单,特别是如果您有一些使用 JavaScript 的经验(这在某种程度上是相似的)。但是,我提供了标记方法,因为我认为这就是您想要的。

这个解决方案基本上由 4 个文件组成:

  1. display.cfm:条目template/page.
  2. components/CountiesDAO.cfc: 一个组件,作为您所在县的数据访问对象,具有相应的 getter。请注意,我正在使用 QoQ 模拟数据库请求。您应该能够使用您的数据源而不是那里的真实数据。
  3. countyForm.js: JavaScript文件用jQueryajax函数获取数据延迟对象并填充html 包含响应数据的容器(有关更多信息,请参阅我在代码中的注释)。
  4. ajaxAPI.cfm:模板echos/outputs所有数据为JSON为您jQueryajax请求。

主要问题是您需要为每个 ajax 请求检索更多 JavaScript 承诺。在 jQuery 中,延迟对象会发生这种情况。

文件如下:

1。 display.cfm:

<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>Page Title</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<body>

<cfset CountiesDAO= new components.CountiesDAO() />
<cfset queryWorkAreaCounties=CountiesDAO.getWorkAreaCounties()>


<cfoutput>
    <select id="county">
        <option value="0">Select</option>
        <cfloop query="queryWorkAreaCounties">
            <option value="#queryWorkAreaCounties.work_area_county_id#">
                #queryWorkAreaCounties.work_area_county_name#
            </option>
        </cfloop>
    </select>
    <div id="cityContainer"></div>
    <div id="streetContainer"></div>
</cfoutput>

<!-- embedded jquery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="countyForm.js"></script>
</body>
</html>

2。 components/CountiesDAO.cfc

<cfcomponent>

    <cffunction name="init">
        <cfset variables.queriesQoQ["work_area_counties"]=createWorkAreaCounties()>
        <cfset variables.queriesQoQ["Work_area_cities"]=createWorkAreaCities()>
        <cfset variables.queriesQoQ["Work_area_streets"]=createWorkAreaStreets()>
        <cfreturn this>
    </cffunction>

    <!--- functions to create Data to emulate a DB with QoQ --->
    <cffunction name="createWorkAreaCounties" 
                access="private" 
                returntype="query"
                hint="create query to simulate a DB data table for QoQ"> 

        <cfset work_area_countyTable= queryNew(
            "work_area_county_id, work_area_county_name",
            "integer,varchar",
            [ 
                {"work_area_county_id":1,"work_area_county_name":"Los Angeles County"}, 
                {"work_area_county_id":2,"work_area_county_name":"Cook County"},
                {"work_area_county_id":3,"work_area_county_name":"Harris County"},
                {"work_area_county_id":4,"work_area_county_name":"Maricopa County"}
            ])/>

        <cfreturn work_area_countyTable> 
    </cffunction> 


    <cffunction name="createWorkAreaCities" 
                access="private" 
                returntype="query"
                hint="create query to simulate a DB data table for QoQ"> 

        <cfset work_area_cityTable= queryNew(
            "work_area_city_id, work_area_city_name, work_area_county_id",
            "integer,varchar,integer",
            [ 
                {"work_area_city_id":1,"work_area_city_name":"Agoura Hills" , "work_area_county_id":1}, 
                {"work_area_city_id":2,"work_area_city_name":"Alhambra" , "work_area_county_id":1}, 
                {"work_area_city_id":3,"work_area_city_name":"Bradbury" , "work_area_county_id":1}, 
            
                {"work_area_city_id":4,"work_area_city_name":"Arlington Heights" , "work_area_county_id":2}, 
                {"work_area_city_id":5,"work_area_city_name":"Bellwood" , "work_area_county_id":2}, 
                {"work_area_city_id":6,"work_area_city_name":"Bridgeview" , "work_area_county_id":2}, 
            
                {"work_area_city_id":7,"work_area_city_name":"Baytown" , "work_area_county_id":3}, 
                {"work_area_city_id":8,"work_area_city_name":"Cove" , "work_area_county_id":3}, 
                {"work_area_city_id":9,"work_area_city_name":"The Woodlands" , "work_area_county_id":3}, 
            
                {"work_area_city_id":10,"work_area_city_name":"Avondale" , "work_area_county_id":4}, 
                {"work_area_city_id":11,"work_area_city_name":"Phoenix" , "work_area_county_id":4}, 
                {"work_area_city_id":12,"work_area_city_name":"Glendale" , "work_area_county_id":4}, 
            ])/>

        <cfreturn work_area_cityTable> 
    </cffunction> 

    <cffunction name="createWorkAreaStreets" 
                access="private" 
                returntype="query"
                hint="create query to simulate a DB data table for QoQ"> 

        <cfset work_area_streetTable= queryNew(
            "work_area_street_id, work_area_street_name, work_area_city_id",
            "integer,varchar,integer",
            [ 
                {"work_area_street_id":1,"work_area_street_name":"Street One Agoura Hills", "work_area_city_id": 1 },
                {"work_area_street_id":2,"work_area_street_name":"Street Two Agoura Hills", "work_area_city_id": 1 }, 
                {"work_area_street_id":3,"work_area_street_name":"Street Three Agoura Hills", "work_area_city_id": 1 }, 

                {"work_area_street_id":4,"work_area_street_name":"Street One Alhambra", "work_area_city_id": 2 },
                {"work_area_street_id":5,"work_area_street_name":"Street Two Alhambra", "work_area_city_id": 2 }, 
                {"work_area_street_id":6,"work_area_street_name":"Street Three Alhambra", "work_area_city_id": 2 },

                {"work_area_street_id":7,"work_area_street_name":"Street One Bradbury", "work_area_city_id": 3 },
                {"work_area_street_id":8,"work_area_street_name":"Street Two Bradbury", "work_area_city_id": 3 }, 
                
                {"work_area_street_id":9,"work_area_street_name":"Street One Arlington Heights", "work_area_city_id": 4 },
                {"work_area_street_id":10,"work_area_street_name":"Street Two Arlington Heights", "work_area_city_id": 4 }, 
                
                {"work_area_street_id":11,"work_area_street_name":"Street One Bellwood", "work_area_city_id": 5 },
                {"work_area_street_id":12,"work_area_street_name":"Street Two Bellwood", "work_area_city_id": 5 }, 
                
                {"work_area_street_id":13,"work_area_street_name":"Street One Bridgeview", "work_area_city_id": 6 },
                {"work_area_street_id":14,"work_area_street_name":"Street Two Bridgeview", "work_area_city_id": 6 }, 
                
                {"work_area_street_id":15,"work_area_street_name":"Street One Baytown", "work_area_city_id": 7 },
                {"work_area_street_id":16,"work_area_street_name":"Street Two Baytown", "work_area_city_id": 7 }, 
                
                {"work_area_street_id":17,"work_area_street_name":"Street One Cove", "work_area_city_id": 8 },
                {"work_area_street_id":18,"work_area_street_name":"Street Two Cove", "work_area_city_id": 8 }, 
                
                {"work_area_street_id":19,"work_area_street_name":"Street One The Woodlands", "work_area_city_id": 9 },
                {"work_area_street_id":20,"work_area_street_name":"Street Two The Woodlands", "work_area_city_id": 9 }, 
                
                {"work_area_street_id":21,"work_area_street_name":"Street One Avondale", "work_area_city_id": 10 },
                {"work_area_street_id":22,"work_area_street_name":"Street Two Avondale", "work_area_city_id": 10 }, 
                
                {"work_area_street_id":23,"work_area_street_name":"Street One Phoenix", "work_area_city_id": 11 },
                {"work_area_street_id":24,"work_area_street_name":"Street Two Phoenix", "work_area_city_id": 11 }, 
                
                {"work_area_street_id":25,"work_area_street_name":"Street One Glendale", "work_area_city_id": 12 },
                {"work_area_street_id":26,"work_area_street_name":"Street Two Glendale", "work_area_city_id": 12 },
            ])/>
        <cfreturn work_area_streetTable>
    </cffunction>


    <cffunction name="getWorkAreaCounties"  
                access="public" 
                returntype="query"
                hint="function to return all counties">  
        
        <cfset work_area_county=queriesQoQ["work_area_counties"]>
        
        <cfquery name="qCity" dbtype="query" >
            SELECT * FROM work_area_county
        </cfquery>
        
        <cfreturn qCity> 
    
    </cffunction>


    <cffunction name="getWorkAreaCitiesByCountyID"  
                access="public" 
                returntype="query"
                hint="function to return all cities of a county"> 
        
        <cfargument type="numeric" name="countyid" required="true">
        
        <cfset work_area_city=queriesQoQ["work_area_cities"]>
        
        <cfquery name="qCity" dbtype="query" >
            SELECT  work_area_city_id, work_area_city_name, work_area_county_id 
            FROM    work_area_city 
            WHERE   work_area_county_id = <cfqueryparam value="#arguments.countyid#" cfsqltype="cf_sql_int">
        </cfquery>
        
        <cfreturn qCity> 
    
    </cffunction>


    <cffunction name="getWorkAreaStreetsByCityID"  
                access="public" 
                returntype="query"
                hint="function to return all streets of a city">  
        
        <cfargument type="numeric" name="cityid" required="true">
        
        <cfset work_area_street=queriesQoQ["work_area_streets"]>
        
        <cfquery name="qStreet" dbtype="query" >
            SELECT  work_area_street_id, work_area_street_name, work_area_city_id 
            FROM    work_area_street 
            WHERE   work_area_city_id = <cfqueryparam value="#arguments.cityid#" cfsqltype="cf_sql_int">
        </cfquery>
        
        <cfreturn qStreet> 
    
    </cffunction> 

</cfcomponent>

3。 countyForm.js

// ajax function
function sendAjaxAndUpdateForm( 
                url, 
                selectorForValue,  
                selectorForHTMLResponse ,  
                callbackFunction ){

    let value = $( selectorForValue ).val();
    
    /* return the ajax request as deferred object with done()/fail(). For more information, please see:
    *  https://api.jquery.com/jquery.ajax/ 
    *  
    */
    return $.ajax({
            method: "GET",
            url: url + value,
            }).done( function( result ) {
                
                //populate HTML div with returned html
                $( selectorForHTMLResponse ).html( result.contentHTML );

                // invoke callback if a callback has been submitted
                if ( callbackFunction && typeof( callbackFunction ) === "function") { 
                    callbackFunction();
                }
            
            }).fail( function( e ) { 
                    
                //log some info and alert about fail
                console.dir( e.responseText );
                alert('Ops! Something went wrong!');

            });
}


$( document ).ready(function() {

    // add listeners to HTML container and make use of callbacks
    $('#county').change(
        function() {
            sendAjaxAndUpdateForm(
                url='ajaxAPI.cfm?work_area_county_id=',
                selectorForValue='#county',
                selectorForHTMLResponse='#cityContainer',
                callbackFunction= function(){ $('#city').change(
                        function() {
                            sendAjaxAndUpdateForm(
                                url='ajaxAPI.cfm?work_area_city_id=',
                                selectorForValue='#city',
                                selectorForHTMLResponse='#streetContainer',
                                callbackFunction=function(){ $('#street').change( 
                                    function(){ alert( 'Street ID:' + $('#street').val() + 'for \'' + $( '#street option:selected' ).text() + '\' selected.' )}  )
                                }
                            );
                     })
                }
            );  
        });
        
});

4. ajaxAPI.cfm

<!--- Function to output content as JSON for a response of the ajax request --->
<cffunction name="outputJSON"  
            access="private" 
            returntype="void"
            hint="function to output data as application/json"> 
    <cfargument type="struct" name="contentStruct" required="true">
    <cfcontent reset = "true">
    <cfheader name="content-type" value="application/json">
    <cfoutput>#serializeJSON( contentStruct )#</cfoutput>
    <cfabort>
</cffunction> 
 
<!--- instantiate Data Access Object Component--->
<cfset CountiesDAO = new components.CountiesDAO() />


<cfif structKeyExists(url, "work_area_county_id") 
      and len( work_area_county_id ) gt 0>

    <cfset queryWorkAreaCities=CountiesDAO.getWorkAreaCitiesByCountyID( url.work_area_county_id )>
    
    <cfsavecontent variable="result.contentHTML">
        <cfoutput>
            <select name="city" id="city" class="form-control">
                <option value="">Select City</option>
                <cfloop query="queryWorkAreaCities">
                    <option value="#queryWorkAreaCities.work_area_city_id#">#queryWorkAreaCities.work_area_city_name#</option>
                </cfloop>
            </select>
        </cfoutput> 
    </cfsavecontent>
        
     <!--- echo json --->
     <cfset outputJSON( result )>

</cfif>



<cfif structKeyExists( url, "work_area_city_id" ) and len( work_area_city_id ) gt 0>
        
    <cfset queryWorkAreaStreets=CountiesDAO.getWorkAreaStreetsByCityID( url.work_area_city_id )>
    
    <cfsavecontent variable="result.contentHTML">
        <cfoutput>
        <select name="street" id="street" class="form-control">
            <option value="">Select Street</option>
            <cfloop query="queryWorkAreaStreets">
                <option value="#queryWorkAreaStreets.work_area_street_id#">#queryWorkAreaStreets.work_area_street_name#</option>
            </cfloop>
        </select>
        </cfoutput>
    </cfsavecontent>

    <!--- echo json --->
    <cfset outputJSON( result )>

</cfif>

上述解决方案还远未完成,但它应该只是给您一个选择,让您可以开始尝试并找点乐子。

(之前开始写这个,后来被拉走了....)

老实说,county.cfm 脚本让我印象深刻,因为它过于努力地想要成为“每个人的一切”:)。它充当 ajax 的 cfinclude 端点,同时检索数据和生成 html。导致代码的可读性和复杂性比 IMO 所必需的要低。

更简洁的方法是将数据检索和 html/dom 操作分开。让 CF 服务器处理数据检索,让客户端操作 DOM。这样只需要两 (2) 个脚本。

创建一个只有 returns 数据的 cfc。然后在表单内,通过 ajax 调用 cfc 函数,并使用响应将 javascript.

填充到 select 列表中

YourComponent.CFC

首先创建一个具有三个远程函数的组件:getCounties()getCities(selected_county_id)getStreets(selected_city_id)。每个函数只运行一个查询,returns 结果作为结构数组,格式为 json 字符串。

<cfcomponent>

    <cffunction name="getCounties" access="remote" returntype="string" returnFormat="plain">
        <!--- query is a function local object, use "local" scope --->
        <cfquery name="local.result">
            SELECT  work_area_county_id, work_area_county_name
            FROM    work_area_county
            ORDER BY work_area_county_name
        </cfquery>
        
        <!--- convert query into workable format: array of structures --->
        <cfreturn serializeJSON(local.result, "struct")>
    </cffunction>
    
    <cffunction name="getCities" access="remote" returntype="string" returnFormat="plain">
        <cfargument name="work_area_county_id" type="numeric" required="true">
        
        <cfquery name="local.result">
            SELECT  work_area_city_id, work_area_city_name
            FROM    work_area_city 
            <!--- correct sql type is "integer" or "cf_sql_intEGER" --->
            WHERE   work_area_county_id = <cfqueryparam value="#arguments.work_area_county_id#" cfsqltype="integer">
            ORDER BY work_area_city_name
        </cfquery>
        
        <cfreturn serializeJSON(local.result, "struct")>
    </cffunction>

    
    <cffunction name="getStreets" access="remote" returntype="string" returnFormat="plain">
        <cfargument name="work_area_city_id" type="numeric" required="true">
        
        <cfquery name="local.result">
           SELECT   work_area_street_id, work_area_street_name
           FROM     work_area_street 
           WHERE    work_area_city_id = <cfqueryparam value="#arguments.work_area_city_id#" cfsqltype="integer">
           ORDER BY work_area_street_name
        </cfquery>
        
        <cfreturn serializeJSON(local.result, "struct")>
    </cffunction>
    
</cfcomponent>

Display.cfm

在表单内,添加 ajax 调用以填充列表。在加载文档时填充“县”列表,并在适当的更改事件中填充“city/street”列表。还有改进的空间,但这里有一个小例子

<script type="text/javascript">
$(document).ready(function()
{
    // On load, populate county list
    $.getJSON( 
        "YourComponent.cfc?method=getCounties",{},
        function(response){
            fillList("#county", response, "work_area_county_id", "work_area_county_name");
            // refresh city and state
            $("#city").trigger("change");

        });     
    
    // When county changes, re-populate cities
    $("#county").on("change", function(evt) {
        
        var county_id = $(this).val();
        $.getJSON( 
            "YourComponent.cfc?method=getCities&work_area_county_id="+ county_id, {},
            function(response){
                fillList("#city", response, "work_area_city_id", "work_area_city_name")
                // refresh city and state
                $("#city").trigger("change");
        });         
    });
    
    // On city change, re-populate streets
    $("#city").on("change", function(evt) {
        $('#street').attr('disabled', true);
        
        var city_id = $(this).val();
        $.getJSON( 
            "YourComponent.cfc?method=getStreets&work_area_city_id="+ city_id, {},
            function(response){
                fillList("#street", response, "work_area_street_id", "work_area_street_name")
        });         
    });
    
    // populates select list with provided data 
    function fillList( id, rows, value, text) {
        // reinitialize
        $( id ).empty().append( $("<option>")
                .text( "Select" )
                .val( 0 )
        ); 
        // populate 
        $.each(rows, function(index, data) {
             $(id).append( $("<option>")
                    .val( data[value] )
                    .text( data[text] )
            ); 
        });
        // enable
        $(id).attr('disabled', false);
    }
});
</script>   

<form name="state_populate">
    <!--- select list must have an "id" --->
    <select id="county" name="county">
        <option value="0">Select</option>
    </select>
    <select id="city" name="city">
        <option value="0">Select</option>
    </select>
    <select id="street" name="street">
        <option value="0">Select</option>
    </select>
</form>

对于未来的观众;我想 post 自己回答我的问题。在等待答案被 posted 时,我一直在尝试让代码正常工作。很多天过去了,我在下面粘贴的是结果。

由于 AndreasRu 和 SOS 的答案都更好,所以我最终没有使用我写的东西。也许有人可以用我的代码作为不该做什么的例子。 :D

我的 CFC:

    component displayname="pull_locations" output="false" {
        public function getCounties(returntype="query") {
            getCounties = queryExecute(
                sql = "SELECT work_area_county_id, work_area_county_name FROM work_area_county"
            );
        return getCounties;
        }
        remote function getCitiesByCounty(required numeric county_id) returnFormat="JSON" {
            getCity = queryExecute(
                sql = "SELECT work_area_county_id, work_area_city_id, work_area_city_name FROM work_area_city WHERE work_area_county_id = :need",
                params = {
                    need: {
                        value: arguments.county_id,
                        type: "cf_sql_integer"
                    }
                }               
            );
            rData = {
                "status" = "success",
                "data" = queryToArray(getCity)
            };
        return serializeJSON(rData);
        }
        remote function getStreetsByCity(required numeric city_id) returnFormat="JSON" {
            getStreet = queryExecute(
                sql = "SELECT work_area_city_id, work_area_street_id, work_area_street_name FROM work_area_street WHERE work_area_city_id = :need",
                params = {
                    need: {
                        value: arguments.city_id,
                        type: "cf_sql_integer"
                    }
                }               
            );
            rData = {
                "status" = "success",
                "data" = QueryToArray(getStreet)
            };
        return serializeJSON(rData);
        }
// Thank you Ben Nadel! :D
        public function queryToArray(required query Data) output=false {
            var LOCAL = StructNew();
            LOCAL.Columns = ListToArray( ARGUMENTS.Data.ColumnList );
            LOCAL.QueryArray = ArrayNew( 1 );
            for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount ; LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
                LOCAL.Row = StructNew();
                for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen( LOCAL.Columns ) ; LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
                    LOCAL.ColumnName = LOCAL.Columns[ LOCAL.ColumnIndex ];
                    LOCAL.Row[ LOCAL.ColumnName ] = ARGUMENTS.Data[ LOCAL.ColumnName ][ LOCAL.RowIndex ];
                }
                ArrayAppend( LOCAL.QueryArray, LOCAL.Row );
            }
        return LOCAL.QueryArray;
        }
    }

我的JavaScript/jQuery:

            function loadCity(county) {
                if(county != '') {
                    $.ajax({
                        url: "cfc/data.cfc?method=getCitiesByCounty",
                        dataType: "json",
                        type: "get",
                        async: false,
                        cache: false,
                        data: {
                            county_id: county,
                        },
                        success: function (response) {
                            response = JSON.parse(response);
                            if(response.status == 'success') {
                                rData = response.data;
                                let html = '<option value="">Select City</option>';
                                rData.forEach(element => {
                                    html += '<option value="'+element.WORK_AREA_CITY_ID+'">'+element.WORK_AREA_CITY_NAME+'</option>';
                                });
                                $('#city').html(html);
                                let html2 = '<option value="">Select Street</option>';
                                $('#street').html(html2);
                            }
                            else {
                                alert('Error occured while pulling City name.');
                            }
                        },
                        error: function(jqXHR, status, error) {
                            console.log(status + ": " + error);
                        }
                    })
                }
            }
            function loadStreet(city) {
                if(city != '') {
                    $.ajax({
                        url: "cfc/data.cfc?method=getStreetsByCity",
                        dataType: "json",
                        type: "get",
                        async: false,
                        cache: false,
                        data: {
                            city_id: city,
                        },
                        success : function(response) {
                            response = JSON.parse(response);
                            if(response.status == 'success') {
                                rData = response.data;
                                let html = '<option value="">Select Street</option>';
                                rData.forEach(element => {
                                    html += '<option value="'+element.WORK_AREA_STREET_ID+'">'+element.WORK_AREA_STREET_NAME+'</option>';
                                });
                                $('#street').html(html);
                            }
                            else {
                                alert('Error occured while pulling Street name.');
                            }
                        },
                        error: function(jqXHR, status, error) {
                            console.log(status + ": " + error);
                        }
                    })
                }
            }