我将向您展示我将如何处理此类任务的示例。我的答案可能不是最好或最干净的解决方案:我过去有过糟糕的编码实践(我仍然倾向于写意大利面,而且我一直在努力反对这样做)。但是,我正在改变那些坏习惯,这很有趣。
我的解决方案是使用 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://stackoverflow.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>
上述解决方案还远未完成,但它应该只是为您提供一个开始玩耍并获得乐趣的选择。