排除嵌套的子项

时间:2009-11-06 16:10:39

标签: jquery

以下脚本使用for:x类名启用/禁用其嵌套表单控件。问题是嵌套的for:y元素在它们不应该被启用时被启用。只有在启用嵌套for:y时才能启用它们。

有人可以为我提供额外的过滤器来排除嵌套for:*类中的表单元素吗?

换句话说,在下面的示例中,当检查losssold时,除for:losssold for:has-buy-sell-agreementtrue内的子元素元素外,has-buy-sell-agreementtrue的所有子输入都应启用{{1}还没有检查过。

所以我认为只想在for: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 个答案:

答案 0 :(得分:2)

您可能正在寻找'not()'过滤器。在您指定的行中,试试这个:

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

或者您提到的变量:

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

我不认为通常的类选择器(点)会起作用,因为jQuery可能认为它是一个伪选择器,如'checked'或'contains。'

<强> EDITED

Okie dokie,我再给它一个镜头:

如果你想缩小输入数量,选择和返回的textrea元素,那么你可以缩小'find'功能或扩大'not'功能。例如,如果您只想对form_1中的表单元素执行操作,那么您可以执行以下操作:

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

这里有关于'not'过滤器的更多细节。 'not'过滤器执行以下操作:

  1. 查找整个文档中其选择器(“非”选择器)指定的所有元素。
  2. 将在步骤1中找到的元素与调用“find”函数中的元素列表进行比较。
  3. 删除两组之间相同的所有元素。
  4. 生成的元素集仅包含原始查找中的元素,但不包含在“非”函数中。
  5. 因此,上面的元素集只包含不在class = for:has-buy-sell-agreement内的input,select和textarea元素。

    哦,我将这个过滤器复制并粘贴到一个简单的html文档上然后就可以了。所以你应该全力以赴!

    后来戴夫, 祝你好运。

答案 1 :(得分:2)

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);
    })

我们的想法是删除任何输入,选择或textareas,这些输入,选择或textareas具有除您所需父级之外的最近父级。

另请注意,我在选择器中对您的:字符进行了双重转义。 :是一个在类名中使用的不寻常的字符,因为它暗示了“伪”选择器,并且还会使jquery绊倒(除非你像我上面那样逃避它)。

祝你好运!

<小时/> 的修改

啊,是的,我们希望禁用通过嵌套的“for:”div传播,而不是启用 ....我们可以修改这个通过移动过滤如下所示。 (过滤器被移动到一个单独的函数,使其更具可读性。)

.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 :(得分:0)

重构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的变体进行了测试,看起来效果很好。

答案 3 :(得分:0)

我最终通过在事件被触发时递归解析子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);
    });
});