通过 AJAX 进行 Coldfusion/Lucee 多条件选择

Posted

技术标签:

【中文标题】通过 AJAX 进行 Coldfusion/Lucee 多条件选择【英文标题】:Coldfusion/Lucee multiple conditional select via AJAX 【发布时间】:2022-01-10 01:45:56 【问题描述】:

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

部分重写需要对基本功能进行几项添加。一个特定的添加是在现有的“县名”->“城市名称”选择字段中添加“街道名称”选择字段。

我发现了这个 *** 问题: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);
        
    );
);

上面的代码在选择“县名”时效果很好。它在第二个选择字段中正确显示“城市名称”。然后我尝试在第三个选择字段中添加“街道名称”,并添加了我“认为”应该适用于 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);
    );

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

代码需要保持第二个选择字段“城市名称”不变,并正确使用具有多个值的 AJAX“url”参数。我知道在参考上述代码的 URL 部分我可能需要一些“类似”的东西:

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

供参考:

    我知道我的代码不是很好,我知道它可以写得更好。我正在努力改进。 我不是全职编码员,但多年来我一直断断续续地编码。我仍然认为自己是 CFML/JavaScript/jQuery 的新手,所以很多方法都超出了我的想象。 代码将用 cfscript 编写,并在未来转换为 CFC。现在我让它变得简单并使用了标签。 我从 display.cfm 中删除了不相关的 HTML 代码。

任何关于上述内容的意见或指导将不胜感激! :D

【问题讨论】:

我建议遵循本文***.com/questions/36893740/… 中的方法。另外,为简单起见,我建议您删除所有格式化代码,直到您的功能正常工作。 谢谢你,丹·布拉库克。现在看。 我查看了您提供的链接,Dan。我试图达到的最终目标非常相似,他们在 CFC 中使用的方法基本上就是我现在所采用的方法。但是,我在不支持 cfform 或 cfselect 的 Lucee 上进行开发,并且我已经学会了完全避免使用这些标签来支持客户端 JavaScript/jQuery。我看不到 YUI 将如何处理 cfselect 标记以及如何将其转换为 jQuery。非常感谢您的建议! :D 您的 loadStreet 函数只使用一个变量。在这种情况下,您应该只需要传递一个值。 needs to keep the second select field "City Name" from changing ... 我想你可能在担心一些不是问题的事情:)。代码只会在I.E.选择“County”更改时更新1选择列表 - >填充“城市”列表,选择“城市”更改 - >填充“街道”列表。因此,填充街道对所选城市名称或县没有影响。 【参考方案1】:

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

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

我也会尝试使用 cfscript 而不是标签,因为使用组件和函数编写 OOP 更简单,尤其是如果您有一些 JavaScript 经验(这有点相似)。但是,我提供了标记方法,因为我认为这是您想要的。

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

    display.cfm:条目模板/页面。 components/CountiesDAO.cfc: 一个组件,它充当具有相应 getter 的县的数据访问对象。请注意,我正在模仿 QoQ 的数据库请求。您应该能够使用您的数据源来代替那里的真实数据。 countyForm.js: 带有 jQ​​uery ajax 函数的 JavaScript 文件,用于获取数据延迟对象并使用响应数据填充 html 容器(更多信息请参见代码中的我的 cmets)。 ajaxAPI.cfm: 为您的 jQuery ajax 请求以 JSON 格式回显/输出所有数据的模板。

主要问题是您需要为每个 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/ 
    *  https://***.com/questions/10931836/should-i-use-done-and-fail-for-new-jquery-ajax-code-instead-of-success-and
    */
    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>

上述解决方案还远未完成,但它应该只是为您提供一个开始玩耍并获得乐趣的选择。

【讨论】:

谢谢! :D 在您的countyform.js 文件中执行AJAX 的有趣方式。我认为不可能像使用#county 变更件那样链接功能。谢谢安德烈亚斯鲁! :D 作为一个附带问题,速度如何?我知道目前数据库中只有一个县及其街道,但是随着时间的推移,数据库会增长并添加越来越多的街道。 感谢您的解决方案标记! :D 关于链:如果您需要更多/更深的链,您可以将每个链码拉出到自己的功能中。关于速度:关键是正确索引数据库表并使用主键(,countyID,cityID)进行SQL-SELECT。可能您可能需要添加带有自动建议功能的搜索框输入文本字段,例如用于街道选择。但是,当使用 like % 运算符结合主键(例如 cityID)过滤街道时,这样的 SQL 在速度上也不应该是一个大问题。 @AndreasRu - 只是好奇,为什么使用 CF 代码而不是 jQuery 来填充列表?似乎更动人.. @SOS - 好问题。这不是黄金法则。只是因为在这种情况下,我(个人)更喜欢创建一个完整的 HTML 块,而不是在浏览器中通过脚本创建它。如果您需要扩展或更改 HTML,您只需在最终的 HTML 代码中进行操作:这是一种“所见即所得”的编辑偏好。【参考方案2】:

(我之前开始写这个,但被拉走了......)

Tbh county.cfm 脚本让我觉得太努力了,不想成为“每个人的一切”:)。它充当 ajax 的 cfinclude 端点,既检索数据又生成 html。导致代码比 IMO 所需的可读性更低且更复杂。

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

创建一个只返回数据的cfc。然后在表单内部,通过 ajax 调用 cfc 函数,并使用响应来使用 javascript 填充选择列表。

YourComponent.CFC

首先创建一个具有三个远程功能的组件:getCounties()getCities(selected_county_id)getStreets(selected_city_id)。每个函数只是简单地运行一个查询并将结果作为结构数组返回,格式为 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>

显示.cfm

在表单中,添加 ajax 调用以填充列表。加载文档时填充“县”列表,并在适当的更改事件上填充“城市/街道”列表。有改进的余地,但这里有一个小例子

<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>

【讨论】:

这是一个不错的干净的解决方案!!!我喜欢纯 JSON 方法,使用 YourComponent.CFC 作为远程 CFC 在服务器端 cfml 脚本中检索纯数据(不涉及任何 HTML)。【参考方案3】:

对于未来的观众;我想发表我自己对我的问题的回答。在等待发布答案的同时,我一直试图让代码正常工作。好多天过去了,下面贴的是结果。

由于 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);
                        
                    )
                
            

【讨论】:

感谢发帖!我更喜欢这种方法,让 javascript 来完成工作。假设您正在调用列表中的 js 方法 on('change'),我们的示例并没有那么不同,$.getJSON() 只是包装了很多样板文件 $.ajax() 的东西。实际上,您的示例中有几个元素比我们的要好,例如用 cfscript 编写而不是 cfml 和 js 错误处理。 (续) 关于 cfc 的一些想法。不要忘记本地化函数变量。此外,由于 cfc 中没有错误处理,如果 ajax 调用出现问题,控制将转移到 jquery error 方法。因此,返回一个带有状态的结构,而不仅仅是一个查询,不会给你带来太多好处。总而言之,很高兴看到几种不同的方法。

以上是关于通过 AJAX 进行 Coldfusion/Lucee 多条件选择的主要内容,如果未能解决你的问题,请参考以下文章

通过Ajax方式上传文件,使用FormData进行Ajax请求

H5 通过Ajax方式上传文件,使用FormData进行Ajax请求

通过 AJAX 进行 Coldfusion/Lucee 多条件选择

对搜索结果的查询集进行排序并通过 ajax 呈现

通过Ajax方式上传文件(图片),使用FormData进行Ajax请求

通过 AJAX 进行跨域资源共享 (CORS)