1

我正在构建一个动态表单系统,它将自动组装一个 HTML 表单并通过使用单个 form.js 文件使其具有交互性,该文件将适用于系统内构建的所有表单。我已经完成了表单系统,并且在大多数情况下 form.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 个小时。仍然没有运气......所以我在这里寻求你的帮助!

用于此的 form.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&nbsp;<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&nbsp;<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">
                &nbsp;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">
                &nbsp;No
            </label>
        </fieldset>
        <div class="dependency" id="radio-test-1-dep" style="display: block;">
            <label for="radio-dep">Radio Dep&nbsp;<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&nbsp;<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">&nbsp;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">&nbsp;No</label>
                            </fieldset>
                            <div class="dependency" id="radio-dep3-1-dep" style="display: none;">
                                <label for="radio-dep4">Radio Dep 4&nbsp;<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&nbsp;<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">
                                                        &nbsp;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">
                                                        &nbsp;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&nbsp;<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">&nbsp;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">&nbsp;Nope</label>
            </fieldset>
            <label for="select-test">Select Test&nbsp;<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>
4

2 回答 2

2

“我想要的功能仅适用于我所在的依赖 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 选择,但我倾向于使用它。

于 2012-05-12T19:49:35.450 回答
0

由于我们不知道“其他元素(不是 div)主要形成输入、标签和字段集”的确切 DOM 树是什么,因此您可以使用此代码在元素内部而不是在其依赖项中查找输入div

更新后的版本:

$("#" + id + " > :input, #" + id + " :not(div) :input").each(function() {
   // ...
});

演示:http: //jsfiddle.net/m7nWK/2/

于 2012-05-12T19:51:49.973 回答