通过 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 + '&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: 带有 jQuery 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 多条件选择