代码之家  ›  专栏  ›  技术社区  ›  David

排除嵌套子级

  •  1
  • David  · 技术社区  · 16 年前

    下面的脚本使用 for:x 类名。问题是嵌套 for:y 元素在不应该启用时被启用。只有在嵌套 对于:Y 启用。

    有人能为我提供一个额外的过滤器来排除嵌套中的表单元素吗 for:* 班级?

    换言之,给出下面的例子,当 losssold 然后检查所有子输入 for:losssold 应启用,但内部子元素元素除外 for:has-buy-sell-agreementtrue 如果 has-buy-sell-agreementtrue 也未选中。

    所以我认为在 有买卖协议吗? .

    <script type="text/javascript">
    $('[class*="for:"]').each(function(){
       var klass=$(this).attr('class'),element;
       var that = this;
       $.each(klass.split(' '),function(index,value){
           if(!value)return;
           if (value.substr(0,4)=='for:')
               element=value.substr(4);
       });
       $('[name="' + $('#'+element).attr('name') + '"]')
           .click(function(){
               $(that).toggleClass('disabled', !$('#'+element).is(':checked'))
                   .find('input,select,textarea') /* insert edge case here */
                   .each(function(){
                       if ($('#'+element).is(':checked'))
                          $(this).removeAttr('disabled');
                       else
                           $(this).attr('disabled','disabled');
                   });
           })
           .trigger('click');
    });
    </script>
    
      <li>What would you like to see happen to your business when you (or a co-owner) die, become disabled, or retire? <br/>
        <ul><li><label><input type="radio" name="loss" id="losssold" value="sold"/> Sold to other Owners/another Business</label>
            <ul class="for:losssold">
              <li>Do you have a buy-sell agreement?<br/>
                <label><input type="radio" name="has-buy-sell-agreement" id="has-buy-sell-agreementtrue" value="true"/> Yes</label> 
                <label><input type="radio" name="has-buy-sell-agreement" id="has-buy-sell-agreementfalse" value="false"/> No</label><br/>
                <ol class="for:has-buy-sell-agreementtrue"> <!-- nested for class; inner elements shouldn't be affected -->
                  <li><label for="buy-sell-last-updated">When was the agreement last updated?</label><br/>
                    <input type="text" name="buy-sell-last-updated" id="buy-sell-last-updated" value=""/>
                  </li>
                  <li>Is the agreement funded?<br/>
                    <label><input type="radio" name="buy-sell-is-funded" id="buy-sell-is-fundedtrue" value="true"/> Yes</label> 
                    <label><input type="radio" name="buy-sell-is-funded" id="buy-sell-is-fundedfalse" value="false"/> No</label>
                  </li>
                </ol>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    
    4 回复  |  直到 15 年前
        1
  •  2
  •   Funka    15 年前

    这个 filter 功能很适合删除需要的项目 匹配一个表达式,这样您就可以更改:

    .find('input,select,textarea') 
    

    进入这个?

    .find('input,select,textarea')
        .filter(function() {
            // return false to remove an element from the set
            return $(this)
                    .closest('[class^="for\\:"]')
                    .hasClass('for:' + element);
        })
    

    其思想是删除任何输入、选择或文本区域,这些区域的父级与所需父级之间的距离最近。

    还请注意,我双重逃脱了你的 : 选择器中的字符。这个 : 在类名中使用是一个不寻常的字符,因为它意味着“伪”选择器,并且还会触发jquery(除非您像我上面所说的那样对其进行转义)。

    祝你好运!


    编辑

    啊,是的,我们想要 停用 通过嵌套的“for:”分隔带向下支撑,但不是 有可能 …我们可以通过移动过滤来如下修改。(过滤器被移动到一个单独的函数,以使其更可读。)

    .find('input,select,textarea')
    .each(function() {
        if ($('#'+element).is(':checked')) {
            if (isDirectDescendant(this, element)) {
                $(this).removeAttr('disabled');
            }
        }
        else {
            $(this).attr('disabled','disabled');
        }
     });
    
    function isDirectDescendant(e, element) {
         return $(e)
                .closest('[class^="for\\:"]')
                .hasClass('for:' + element);
    }
    
        2
  •  2
  •   btelles    15 年前

    您可能正在查找“not()”筛选器。在指定的行,尝试以下操作:

    .find('input,select,textarea').not("[class='for\\:has-buy-sell-agreementtrue'] *")
    

    或者使用您提到的变量:

    .find('input,select,textarea').not("[class='for\\:" + element + "true'] *")
    

    我认为通常的类选择器(dot)不起作用,因为jquery可能认为它是一个伪选择器,如“checked”或“contains”。

    编辑

    Okie Dokie,我再给它一次机会:

    如果要缩小返回的输入、选择和textrea元素的数量,可以缩小“find”函数的范围,也可以扩大“not”函数的范围。例如,如果您只想对表单1内的表单元素执行操作,那么可以执行以下操作:

    .find('#form_1 input, #form_1 select, #form_1 textarea').not("[class='for\\:" + element + "true'] *");
    

    下面是关于“not”过滤器的更多详细信息。 “not”筛选器执行以下操作:

    1. 查找中的所有元素 整个的 其选择器(非选择器)指定的文档。
    2. 将步骤1中找到的元素与调用“find”函数中的元素列表进行比较。
    3. 删除两个集合之间相同的所有元素。
    4. 生成的元素集仅包括原始查找中的元素,但不在“not”函数中。

    因此,上面的元素集将只包括不在class=for:has buy-sell协议中的输入、选择和文本区域元素。

    哦,我把这个过滤器复制粘贴到一个简单的HTML文档上,它就工作了。所以你应该准备好了!

    后来戴夫, 祝你好运。

        3
  •  0
  •   Ben Koehler    15 年前

    重新构造HTML是关键:

    <li>What would you like to see happen to your business when you (or a co-owner) die, become disabled, or retire? <br/>
        <ul>
            <li>
                <input type="radio" name="loss" id="losssold" value="sold"/>
                <label for="losssold">  Sold to other Owners/another Business
                </label>
                <ul class="nestedList">
                    <li>Do you have a buy-sell agreement?<br/>
                        <input type="radio" name="has-buy-sell-agreement" id="has-buy-sell-agreementtrue" value="true"/>
                        <label for="has-buy-sell-agreementtrue">    Yes
                        </label> 
                        <input type="radio" name="has-buy-sell-agreement" id="has-buy-sell-agreementfalse" value="false"/>
                        <label for="has-buy-sell-agreementfalse">   No
                        </label>
                        <br/>
                        <ol class="nestedList">
                            <li>
                                <label for="buy-sell-last-updated">
                                    When was the agreement last updated?
                                </label>
                                <br/>
                                <input type="text" name="buy-sell-last-updated" id="buy-sell-last-updated" value=""/>
                            </li>
                            <li>Is the agreement funded?
                                <br/>
                                <input type="radio" name="buy-sell-is-funded" id="buy-sell-is-fundedtrue" value="true"/> 
                                <label for="buy-sell-is-fundedtrue">    Yes
                                </label> 
                                <input type="radio" name="buy-sell-is-funded" id="buy-sell-is-fundedfalse" value="false"/> 
                                <label for="buy-sell-is-fundedfalse">   No
                                </label>
                            </li>
                        </ol>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    

    我感动了你 <input> 标签之外的标记,以便所有输入都具有 <li> . 这使得jQuery更容易想到。以下是我的资料:

    $('.nestedList input, .nestedList select, .nestedList textarea').attr('disabled', 'disabled');
    
    $('input:radio').click(function() {
        $('[name="' + $(this).attr('name') + '"]').each(function() {
            if($(this).val() != 'false')
            {
                if(this.checked == true)
                {
                    $(this).siblings(".nestedList").children('li').children('input, select, textarea').removeAttr('disabled');
                } else
                {
                    $(this).siblings(".nestedList").children('li').children('input, select, textarea').attr('disabled','disabled');
                }
            }
        });
    });
    

    我已经用你的HTML的变体测试过这个,并且看起来工作得很好。

        4
  •  0
  •   David    15 年前

    我最终通过递归地解析这个孩子来解决这个问题。 for^= 激发事件时的元素。

    $(function(){
        $('[class^="for:"]').each(function(){
            var that=this;
            function getElement(forElement){
                 var klass=$(forElement).attr('class'),element;
                 $.each(klass.split(' '),function(index,value){
                     if(!value)return;
                     if(value.substr(0,4)=='for:'){
                         element=value.substr(4);
                         return false;
                     }
                 });
                 return '#' + element;
             }
             function parse(forElement){
                 var element = getElement(forElement);
                 if (element == '#') return;
                 $(forElement)
                     .toggleClass('disabled', !$(element).is(':checked'))
                     .find('input,select,textarea')
                         .each(function(){
                             if ($(element).is(':checked'))
                                 $(this).removeAttr('disabled');
                             else
                                 $(this).attr('disabled','disabled');
                         })
                     .end()
                     .find('[class^="for:"]')
                         .each(function() { parse(this); });
             }
             var element = getElement(this);
             $('[name="' + $(element).attr('name') + '"]')
                 .click(function() { parse(that); });
             parse(this);
        });
    });