我正在构建一个动态表单系统,该系统将自动组装一个HTML表单,并使用单个表单.js文件使其具有交互性,该文件将处理系统内构建的所有表单。我已经完成了表单系统,并且在大多数情况下,表单.js已经完成,除了嵌套div的错误之外。
一点背景:如果需要,我会发布我正在测试的表格,但我认为这足以解释我的需求。我正在使用一种将问题依赖项放在div 中的表单,以便如果问题得到回答,则会显示依赖项。为了更好地理解它是如何工作的,表单系统允许无限嵌套依赖项。如果问题 1 具有依赖项问题,并且该依赖项具有依赖项,而问题 2 具有依赖项,则如下所示:
Question 1:
-> Dependency Question 1-1
-> Dependency Question 1-1-1
Question 2
-> Dependency Question 2-1
依赖项的每个部分都进入自己的包含样式和组织的div:
<form>
<!-- Other elements (not div) mainly form input, labels, and fieldsets-->
<div id="dep-1" class="dependency">
<!-- Other elements (not div) mainly form input, labels, and fieldsets-->
<div id="dep-1-2" class="dependency">
<!-- Other elements (not div) mainly form input, labels, and fieldsets-->
<div id="dep-2-1" class="dependency">
<!-- Other elements (not div) mainly form input, labels, and fieldsets-->
</div>
</div>
</div>
</form>
ID仅用于显示,它们由表单系统自动化。
我的问题:我让每件事都按照我想要的方式工作,至少我是这么认为的。我在使用主 js 文件来控制所有表单时遇到的唯一问题是嵌套的div。在表单加载时,我使用 jQuery 禁用所有依赖项以防止它们提交表单。问题是当我重新打开它们时。我想要的功能仅适用于我所在的依赖项div,以便仅为该div 启用 :input,而不是在子div 中。目前,父div 中的所有子div :input 都已启用。我已经尝试了许多方法来防止它进入儿童div并在Google和SO上花费了2个多小时。还是没有运气...所以我在这里寻求你的帮助!
表单.js用于此目的的代码
function _toggleDependencyContainer(id, result) {
if (result === true) {
// Allow only input of parent dependency div, not children dependency divs
$('#'+id).find(':input').each(function() { // **THIS LINE IS THE ISSUE!!**
$(this).removeAttr("disabled");
});
$('#'+id).slideDown();
} else {
// Disable all children input through all child divs
$('#'+id).slideUp().find(':input').each(function() {
$(this).attr("disabled", "disabled")
});
}
}
function _toggleElementDependencies(element) {
if (element.type === undefined) {
console.log('element.type is undefined');
return;
}
// Get the dependency ID and result then toggle
switch(element.type.toLowerCase()) {
case 'select':
case 'select-one':
case 'select-multiple':
$("#"+element.id+" option").each(function () {
var id = element.id+'-'+this.value+'-dep';
var result = this.selected;
if (id === undefined || id == null) {
return;
}
_toggleDependencyContainer(id, result);
});
return;
break;
case 'radio':
case 'checkbox':
var id = element.id+'-dep';
var result = $(element).is(':checked');
break;
case 'file':
case 'password':
case 'text':
case 'textarea':
var id = element.id+'-dep';
var result = ( $.trim( $(element).val() ) ) ? true : false;
break;
default:
return;
break;
}
if (id === undefined || id == null) {
return;
}
_toggleDependencyContainer(id, result);
}
$(document).ready(function() {
$('.dependency').hide(); // hide all dependencies
//
// Scan page for forms
// Loop through each form and process the elements to toggle dependencies
$('form').each(function(i) {
// Find all the input elements
$('#'+this.id).find(':input').not(':disabled').each(function(i) {
_toggleElementDependencies(this);
});
});
// Monitor form elements to toggle dependencies
$(':input').blur(function() {
_toggleElementDependencies(this);
});
$(':radio, :checkbox').click(function() {
$('input[name="'+this.name+'"]').each(function(i) {
_toggleElementDependencies(this);
});
});
$('select').change(function() {
_toggleElementDependencies(this);
});
});
我希望一些jQuery大师可以给我我缺少的代码片段。我尝试使用 .not(( 选择器,但我认为我为儿童div 使用了错误的标识符。我试过:
$('#'+id).not('div>div').find(':input').each(...);
$('#'+id).not('div:first').find(':input').each(...);
$('#'+id).not('div:first-chil').find(':input').each(...);
$('#'+id).not('div').find(':input').each(...);
等等,但我认为我错过了一些简单的东西..
编辑我正在添加我用来帮助理解布局的表单
<form method="post" action="/_projects/newForm/" id="test" name="test">
<fieldset>
<legend>One</legend><label for="first-name">First Name <span class="required-icon">*</span></label>
<input type="text" value="test" class="required" title="First Name" id="first-name" name="first_name">
<div class="dependency" id="first-name-dep" style="display: block;">
<label for="first-name2">First Name 2</label>
<input type="text" title="First Name 2" id="first-name2" name="first_name2">
<div class="dependency" id="first-name2-dep" style="display: none;">
<label for="first-name3">First Name 3</label>
<textarea title="First Name 3" id="first-name3" name="first_name3" disabled="disabled"></textarea>
</div>
</div>
<label for="last-name">Last Name</label>
<input type="text" title="Last Name" id="last-name" name="last_name">
<label for="last-name2">Last Name2</label>
<input type="text" title="Last Name2" id="last-name2" name="last_name2">
<label for="radio-test">Radio Test <span class="required-icon">*</span></label>
<fieldset class="options-cage" id="options-cage-radio-test">
<label for="radio-test-1">
<input type="radio" class="required" title="Yes" value="1" name="radio_test" id="radio-test-1">
Yes
</label>
<label for="radio-test-2">
<input type="radio" class="required" title="No" checked="checked" value="2" name="radio_test" id="radio-test-2">
No
</label>
</fieldset>
<div class="dependency" id="radio-test-1-dep" style="display: block;">
<label for="radio-dep">Radio Dep <span class="required-icon">*</span></label>
<input type="text" class="required" title="Radio Dep" id="radio-dep" name="radio_dep">
<div class="dependency" id="radio-dep-dep" style="display: none;">
<label for="radio-dep2">Radio Dep 2</label>
<input type="text" title="Radio Dep 2" id="radio-dep2" name="radio_dep2" disabled="disabled">
<div class="dependency" id="radio-dep2-dep" style="display: none;">
<label for="radio-dep3">Radio Dep 3 <span class="required-icon">*</span></label>
<fieldset class="options-cage" id="options-cage-radio-dep3">
<label for="radio-dep3-1">
<input type="radio" class="required" title="Yes" value="1" name="radio_dep3" id="radio-dep3-1" disabled="disabled"> Yes</label>
<label for="radio-dep3-2">
<input type="radio" class="required" title="No" checked="checked" value="2" name="radio_dep3" id="radio-dep3-2" disabled="disabled"> No</label>
</fieldset>
<div class="dependency" id="radio-dep3-1-dep" style="display: none;">
<label for="radio-dep4">Radio Dep 4 <span class="required-icon">*</span></label>
<input type="text" class="required" title="Radio Dep 4" id="radio-dep4" name="radio_dep4" disabled="disabled">
<div class="dependency" id="radio-dep4-dep" style="display: none;">
<label for="radio-dep5">Radio Dep 5</label>
<input type="text" title="Radio Dep 5" id="radio-dep5" name="radio_dep5" disabled="disabled">
<div class="dependency" id="radio-dep5-dep" style="display: none;">
<label for="radio-dep6">Radio Dep 6 <span class="required-icon">*</span></label>
<fieldset class="options-cage" id="options-cage-radio-dep6">
<label for="radio-dep6-1">
<input type="checkbox" class="required" title="Yes" value="1" name="radio_dep6" id="radio-dep6-1" disabled="disabled">
Yes
</label>
<label for="radio-dep6-2">
<input type="checkbox" class="required" title="No" checked="checked" value="2" name="radio_dep6" id="radio-dep6-2" disabled="disabled">
No
</label>
</fieldset>
</div>
</div>
</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Two</legend><label for="last-name3">Last Name3</label>
<input type="text" title="Last Name3" id="last-name3" name="last_name3">
<label for="checkbox-test">Checkbox Test <span class="required-icon">*</span></label>
<fieldset class="options-cage" id="options-cage-checkbox-test">
<label for="checkbox-test-10">
<input type="checkbox" class="required" title="Yup" value="10" name="checkbox_test[]" id="checkbox-test-10"> Yup</label>
<label for="checkbox-test-12">
<input type="checkbox" class="required" title="Nope" checked="checked" value="12" name="checkbox_test[]" id="checkbox-test-12"> Nope</label>
</fieldset>
<label for="select-test">Select Test <span class="required-icon">*</span></label>
<select title="Select Test" id="select-test" name="select_test" class="input-select required">
<option value="">- Please Select</option>
<option value="1">one</option>
<option value="2">two</option>
</select>
</fieldset>
<fieldset>
<input type="hidden" value="test" id="formID" name="formID">
<input type="hidden" value="dd7c7fae86db8988669231b67ce637138aa6c180" id="csrf" name="csrf">
<input type="submit" value="Submit">
<input type="reset" title="Reset the form?" value="Reset">
</fieldset>
</form>
"我想要的功能只是针对我所在的依赖项div,只启用该div 的 :input,而不是在子div 中。">
如果我理解了所有这些,你会改变这个:
$('#'+id).find(':input').each(function() {
对此:
$('#'+id).children(':input').each(function() {
我的理解是,您只想针对子输入。您有时似乎使用术语"孩子"来指代所有祖先,而实际上,孩子只意味着下一个嵌套级别。
为了继续祖先的隐喻,更深层次嵌套的元素将是孙子、曾孙等。
.find()
方法查看所有祖先,而.children()
方法仅查看儿童。
旁注:您无需显式编写.each()
代码。您可以这样做:
$('#'+id).find(':input').removeAttr('disabled');
该方法将应用于所有匹配项。
事实证明,由于容器fieldset
,DOM 选择稍微复杂一些,我们可以这样做:
$('#' + id + ' > :input, #' + id + ' > fieldset :input')
相当于这个:
$('#' + id).children(':input').removeAttr('disabled')
$('#' + id).children('fieldset').find(':input').removeAttr('disabled')
我倾向于更喜欢,尽管可以缓存初始 ID 选择。
由于我们不知道"其他元素(不是div(主要形成输入、标签和字段集"的确切 DOM 树是什么,您可以使用此代码查找元素内部的输入,但不查找其依赖项div
s 中的输入。
更新版本:
$("#" + id + " > :input, #" + id + " :not(div) :input").each(function() {
// ...
});
演示:http://jsfiddle.net/m7nWK/2/