尝试构建一个链式选择表单,当我使用.on('change')使用$ .ajax请求获得所需数量的选项时,我已经完成了这个,但是当我开始失控时需要根据先前的选择显示可能存在或不存在的4个以下的下拉选项。有没有办法使用promises或其他东西重构此代码。也许指出我正确的方向?这是一个示例代码段。
$('#model').on('change',function(){
var modelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
if(modelID){
$.ajax({
url:'lib/ajaxData.php',
type: "POST",
data:{
"action" : 'getsubmodels',
"makeset_id" : makesetID,
"yearset_id" : yearsetID,
"model_id" : modelID
},
dataType: "html",
success:function(html){
if (html) {
// found a submodel
$('#submodel').html(html);
$('#submodel').on('change',function(){
var submodelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
var modelsetID = $('#model').val();
$.ajax({
type:'POST',
url:'lib/ajaxData.php',
data: {
"action" : 'getbodytypes',
"year": yearsetID,
"make" : makesetID,
"model" : modelsetID,
"submodel" : submodelID
},
success:function(html){
// found a bodytype
if(html) {
$('#bodytype').html(html);
$('#bodytype').on('change',function(){
//more dropdowns
}
}
}
});
});
}else{
//no submodel
}
}
});
}else{
$('.product').html('Select Some Values');
}
});
已编辑以显示HTML
以下是HTML的外观,除非该选项可用,否则会隐藏一些下拉列表。
<div class="select-boxes row">
<div class="small-12 medium-1 columns">
<select name="year" id="year">
<option value="">Year </option>
</select>
</div>
<div class="small-12 medium-1 columns">
<select name="make" id="make">
<option value="">Make</option>
</select>
</div>
<div class="small-12 medium-1 columns end">
<select name="model" id="model">
<option value="">Model</option>
</select>
</div>
<div class="small-12 medium-1 columns end submodel modifier" style="display:none;">
<select name="submodel" id="submodel">
<option value="">Submodel</option>
</select>
</div>
<div class="small-12 medium-1 columns end bodytype modifier" style="display:none;">
<select name="bodytype" id="bodytype">
<option value="">BodyType</option>
</select>
</div>
<div class="small-12 medium-1 columns end enginetype modifier" style="display:none;">
<select name="engine" id="engine">
<option value="">EngineType</option>
</select>
</div>
<div class="small-12 medium-1 columns end drivetype modifier" style="display:none;">
<select name="drive" id="drive">
<option value="">DriveType</option>
</select>
</div>
</div>
答案 0 :(得分:1)
更具可读性
$('#model').on('change', modelOnChange);
function modelOnChange() {
var modelID = $(this).val(),
yearsetID = $('#year').val(),
makesetID = $('#make').val();
(modelID) ? doStuff(modelID, yearsetID, makesetID) : doStuffIfNoId();
}
function doStuff(modelID, yearsetID, makesetID) {
getSubModels(afterGetSubModels);
}
function doStuffIfNoId() {
$('.product').html('Select Some Values');
}
function getSubModels(callback) {
$.ajax({
url : 'lib/ajaxData.php',
type : "POST",
data : {
"action" : 'getsubmodels',
"makeset_id": makesetID,
"yearset_id": yearsetID,
"model_id" : modelID
},
dataType: "html",
success : function (html) {
if (callback)callback(html);
}
});
}
function afterGetSubModels(html) {
if (html) doStuffModels();
}
function doStuffModels() {
// found a submodel
$('#submodel').html(html);
$('#submodel').on('change', subModuleChange);
}
function subModuleChange() {
var submodelID = $(this).val(),
yearsetID = $('#year').val(),
makesetID = $('#make').val(),
modelsetID = $('#model').val();
getBodyTypes(afterGetBodyTypes);
function getBodyTypes(callback) {
$.ajax({
type : 'POST',
url : 'lib/ajaxData.php',
data : {
"action" : 'getbodytypes',
"year" : yearsetID,
"make" : makesetID,
"model" : modelsetID,
"submodel": submodelID
},
success: function (html) {
if (callback)callback(html);
}
});
}
function afterGetBodyTypes(html) {
// found a bodytype
if (html) {
$('#bodytype').html(html);
$('#bodytype').on('change', function () {
//more dropdowns
});
}
}
}
答案 1 :(得分:0)
首选方法是使用延迟事件而不是回调语法。在jQuery 1.5中引入时,他们使用的语法与ES6的承诺非常相似。这是SitePoint的主题tutorial。
简而言之,您不是传递回调函数,而是将.done()
,.fail()
,.always()
和.then()
方法链接到{{1调用。 $.when
调用是$.ajax()
方法的参数。
以下是一个例子:
$.when()
希望这有点帮助!
答案 2 :(得分:0)
因为#submodel
已经存在于所有这一切的开头并且没有被替换,所以你可以简单地将该甚至处理程序拉出嵌套。它不需要在里面。我还建议您将ajax处理切换为使用promises,因为它可以防止将来在复合操作上嵌套。
#bodytype
似乎已经存在并且没有被替换,所以你可以为它做同样的事情。只需将事件处理程序从嵌套中拉出来。
如果动态替换或加载了这些元素中的任何一个,则可以使用委派事件处理。我将在下面显示两个版本的代码。
这是一个版本,假设#submodel
和#bodytype
是常量而不是替换(如果更换子html则没问题):
$('#model').on('change',function(){
var modelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
if (modelID) {
$.ajax({
url:'lib/ajaxData.php',
type: "POST",
data: {
"action" : 'getsubmodels',
"makeset_id" : makesetID,
"yearset_id" : yearsetID,
"model_id" : modelID
},
dataType: "html",
}).then(function(html){
if (html) {
// found a submodel
$('#submodel').html(html);
} else {
//no submodel
}
});
} else {
$('.product').html('Select Some Values');
}
});
$('#submodel').on('change',function(){
var submodelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
var modelsetID = $('#model').val();
$.ajax({
type:'POST',
url:'lib/ajaxData.php',
data: {
"action" : 'getbodytypes',
"year": yearsetID,
"make" : makesetID,
"model" : modelsetID,
"submodel" : submodelID
}
}).then(function(html){
// found a bodytype
if(html) {
$('#bodytype').html(html);
}
});
});
$('#bodytype').on('change',function(){
//more dropdowns
});
并且,如果动态替换了这些元素中的另一个,那么这是一个使用委托事件处理的版本,可以使用它。委托事件处理使用不同形式的jQuery .on()
。而不是:
$(selector).on(event, fn);
它使用:
$(staticParentSelector).on(event, dynamicElementSelector, fn);
从技术上讲,这是如何工作的,它将事件处理程序分配给静态父对象(一个不动态替换的对象)。然后,它使用事件冒泡(其中在子级上发生的事件在父级层次结构中冒泡并提供给父元素)。当事件命中父元素时,jQuery委托事件处理检查该事件是否源于我们感兴趣的子选择器。如果是,则触发事件处理程序。这适用于动态创建的元素,因为没有事件处理程序实际附加到您感兴趣的动态创建的元素。相反,当它们冒泡到父级并且从那里触发事件处理程序时,会捕获该动态元素上发生的事件。
我们不会一直使用委托事件处理,因为它有一些应该注意的缺点。它的CPU效率要低一些,因为父母可能不得不检查来自很多不同孩子的大量冒泡事件,只是为了找到它正在寻找的那个。并且,您不能在其生命周期的早期处理该事件,因此如果您试图阻止默认操作(例如阻止提交表单),则事件冒泡时可能为时已晚给父母。而且,并非所有事件都不会冒泡(尽管大多数都是这样)。这些问题似乎都不适合你,所以这里是使用委托事件处理的代码。
由于我不知道你的HTML,我只选择document.body
作为附加事件处理程序的静态元素。通常最好选择在实际HTML中没有被替换的最接近的父元素,这可能是一个更接近的父元素。
$(document.body).on('change', '#model', function(){
var modelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
if (modelID) {
$.ajax({
url:'lib/ajaxData.php',
type: "POST",
data: {
"action" : 'getsubmodels',
"makeset_id" : makesetID,
"yearset_id" : yearsetID,
"model_id" : modelID
},
dataType: "html",
}).then(function(html){
if (html) {
// found a submodel
$('#submodel').html(html);
} else {
//no submodel
}
});
} else {
$('.product').html('Select Some Values');
}
});
$(document.body).on('change', '#submodel', function(){
var submodelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
var modelsetID = $('#model').val();
$.ajax({
type:'POST',
url:'lib/ajaxData.php',
data: {
"action" : 'getbodytypes',
"year": yearsetID,
"make" : makesetID,
"model" : modelsetID,
"submodel" : submodelID
}
}).then(function(html){
// found a bodytype
if(html) {
$('#bodytype').html(html);
}
});
});
$(document.body).on('change', '#bodytype', function(){
//more dropdowns
});
在问题的另一部分中,如果您只想在选择非默认值时显示下一个下拉列表,您可以这样做:
$(".select-boxes select").on("change", function(e) {
// if we have a value here, then reveal the next select div
if ($(this).val()) {
// get parent div, then get next div, then show it
$(this).closest(".small-12").next().show();
}
});
答案 3 :(得分:0)
我发现你有很多嵌套的ajax
电话。
这就是我们所说的
Callback hell
我建议您使用Ajax的Promise
方式代替回调,但这也会导致Promise hell
。
因此,唯一的解决方案是使用ES2017 async/await语法;所以,像这样改变你的代码。
$('#model').on('change',async function(){
var modelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
if (!modelID)
return $('.product').html('Select Some Values');
try {
var html = await $.ajax({
url:'lib/ajaxData.php',
type: "POST",
data:{
"action" : 'getsubmodels',
"makeset_id" : makesetID,
"yearset_id" : yearsetID,
"model_id" : modelID
},
dataType: "html"
}) //If the ajax fail with 404, 500, or anything error, will be catched below...
if (!html)
return console.log('No submodel');
$('#submodel').html(html);
$('#submodel').on('change', async function(){
var submodelID = $(this).val();
var yearsetID = $('#year').val();
var makesetID = $('#make').val();
var modelsetID = $('#model').val();
try {
var html2 = await $.ajax({
type:'POST',
url:'lib/ajaxData.php',
data: {
"action" : 'getbodytypes',
"year": yearsetID,
"make" : makesetID,
"model" : modelsetID,
"submodel" : submodelID
}
})
if (!html2)
return console.log('No submodel 2')
$('#bodytype').html(html);
$('#bodytype').on('change',async function(){
//more dropdowns
})
} catch (e) {
console.log('Error 2nd ajax', e)
}
})
} catch (e) {
console.log('Error in 1st ajax', e)
}
})