我目前正在自學(重新自學)JavaScript 和 jQuery,以便重寫在 Lucee 上運行的遺留應用程式。
部分重寫需要對基本功能進行一些添加。一個特定的添加是將“街道名稱”選擇欄位添加到現有的“縣名”->“城市名稱”選擇欄位。
我發現了這個 StackOverflow 問題:Coldfusion conditional select option 在 IE9、Chrome 和 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" >
<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" >
<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);
}
});
});
The code above works well when selecting "County Name". It displays the "City Name" in the second select field properly. I then tried to add in the third select field "Street Name" and added what I "think" should work for the CFML and HTML pieces. When I got to the JS part of the code I hit a brick wall head on. I can't seem to find, perhaps for lack of the right search terms, how to add an additional AJAX call.
I found this question: Parallel asynchronous Ajax requests using jQuery
There were multiple answers but the closest one I "think" that's relevant to my question is this:
$.whenAll({
val1: $.getJSON('/values/1'),
val2: $.getJSON('/values/2')
})
.done(function (results) {
var sum = results.val1.value results.val2.value;
$('#mynode').html(sum);
});
I believe they are called "promise"?
The code needs to keep the second select field "City Name" from changing and to properly use the AJAX "url" parameter with multiple values. I know I probably need something "similar" to this for the URL part in reference to the above code:
url:'includes/county.cfm?work_area_county_id=' value '&work_area_city_id=' value
For consideration:
- I know my code is not great and I know it could be written better. I'm working hard to improve.
- I'm not a full time coder but I have been coding off and on for many years. I still consider myself a newbie with CFML/JavaScript/jQuery so a lot of the methodology goes over my head.
- The code will be written in cfscript and converted to a CFC in the future. For now I made it simple and used tags.
- I removed the irrelevant HTML code from the display.cfm.
Any input or guidance on the above would be greatly, greatly appreciated! :D
uj5u.com熱心網友回復:
我將向您展示我將如何處理此類任務的示例。我的答案可能不是最好或最干凈的解決方案:我過去有過糟糕的編碼實踐(我仍然傾向于寫意大利面條,我一直在努力反對這樣做)。但是,我正在改變那些壞習慣,這很有趣。
我的解決方案是用 OOP 方法撰寫的。我真的建議每個人都嘗試走這條路,因為這很快就會讓人感覺更自然:感覺很好,尤其是當您需要修復或擴展代碼時。
我也會嘗試使用 cfscript 而不是標簽,因為用組件和函式撰寫 OOP 更簡單,特別是如果你有一些 JavaScript 經驗(這有點相似)。但是,我提供了標記方法,因為我認為這正是您想要的。
該解決方案基本上由 4 個檔案組成:
- display.cfm:條目模板/頁面。
- components/CountiesDAO.cfc:一個組件,用作您的縣的資料訪問物件,具有相應的 getter。請注意,我正在用 QoQ 模擬資料庫請求。您應該能夠使用您的資料源來代替那里的真實資料。
- CountyForm.js:帶有 jQ??uery ajax 函式的 JavaScript 檔案,用于獲取資料延遲物件并使用回應資料填充 html 容器(有關更多資訊,請參閱我在代碼中的注釋)。
- ajaxAPI.cfm:為您的 jQuery ajax 請求回顯/輸出所有資料作為 JSON 的模板。
主要問題是您需要為每個 ajax 請求檢索更多的 JavaScript 承諾。在 jQuery 中,延遲物件會發生這種情況。
以下是檔案:
1.顯示.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.countryForm.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>
上面的解決方案還遠未完成,但它應該只是讓您可以選擇開始玩樂并獲得一些樂趣。
uj5u.com熱心網友回復:
(我之前開始寫這個,但被拉走了......)
Tbhcounty.cfm劇本讓我覺得太努力了,無法成為“所有人的一切”:)。它充當ajax的 cfinclude和端點,既檢索資料又生成 html。因此,結果比 IMO 需要的可讀性更差且更復雜。
更簡潔的方法是將資料檢索和 html/dom 操作分開。創建一個只回傳資料的 cfc。然后在客戶端,通過 ajax 呼叫 cfc 函式并使用回應用 javascript 填充選擇串列。
你的組件.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){
$('#street').attr('disabled', true);
$('#city').attr('disabled', true);
fillList("#county", response, "work_area_county_id", "work_area_county_name")
});
// When county change, re-populate cities
$("#county").on("change", function(evt) {
$('#city').attr('disabled', true);
$('#street').attr('disabled', true);
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")
});
});
// 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>
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/378981.html
標籤:javascript jquery ajax coldfusion lucee
下一篇:貓鼬陣列物件中的遞增數字
