【问题标题】:Disabling fieldsets does not work as expected禁用字段集无法按预期工作
【发布时间】:2020-03-20 11:09:17
【问题描述】:

在我的演示表单中,字段集在按钮选择时按顺序启用。因此,检查第一个字段集中的按钮会启用第二个,依此类推。

如果未选中第一个字段集中的所有复选框,则应重置表单,然后应再次禁用第二到第四个字段集。但这不是发生的事情。第二个字段集以某种方式保持启用状态。这里有什么问题?

document.addEventListener("DOMContentLoaded", _ => {
  const form = document.forms[0]

  // First, disable all fieldsets except the first

  function disableFieldsets() {
    const disabledFieldsets = form.querySelectorAll(
      "section:not(:first-of-type) fieldset"
    )

    for (let i = 0; i < disabledFieldsets.length; i++) {
      disabledFieldsets[i].disabled = true
    }
  }

  disableFieldsets()

  // Sequentially enable fieldsets on selection

  const sections = form.querySelectorAll("section")

  sections.forEach(section => {
    section.addEventListener("change", function() {
      let nextFieldset = this.nextElementSibling.querySelector("fieldset")

      if (nextFieldset) {
        nextFieldset.disabled = false
      }
    })
  })

  // Reset form and disable fieldsets after all inputs in the first fieldset are deselected

  const firstFieldsetButtons = form.querySelectorAll("[name=First]")
  let isChecked = false

  firstFieldsetButtons.forEach(firstFieldsetButton => {
    firstFieldsetButton.addEventListener("click", function(e) {
      if (this.checked) {
        isChecked = true
      } else {
        form.reset()
        disableFieldsets()
      }
    })
  })
})
<form method=post action=submit>    
  <section>
  <fieldset>
    <legend>First Fieldset</legend>
    <label><input type=checkbox name=First value=A>A</label>
    <label><input type=checkbox name=First value=B>B</label>
    <label><input type=checkbox name=First value=C>C</label>
  </fieldset>
  </section>
  
  <section>
  <fieldset>
    <legend>Second Fieldset</legend>
    <label><input type=radio name=Second value=1.1>1.1</label>
    <label><input type=radio name=Second value=1.2>1.2</label>
    <label><input type=radio name=Second value=1.3>1.3</label>
  </fieldset>
  </section>
  
  <section>
  <fieldset>
    <legend>Third Fieldset</legend>
    <label><input type=radio name=Third value=2.1>2.1</label>
    <label><input type=radio name=Third value=2.2>2.2</label>
    <label><input type=radio name=Third value=2.3>2.3</label>
  </fieldset>
  </section>
  
  <section>
  <fieldset>
    <legend>Fourth Fieldset</legend>
    <label><input type=radio name=Fourth value=3.1>3.1</label>
    <label><input type=radio name=Fourth value=3.2>3.2</label>
    <label><input type=radio name=Fourth value=3.3>3.3</label>
  </fieldset>
  </section>
  
  <input type=submit value=Submit>
</form>

【问题讨论】:

    标签: javascript forms checkbox ecmascript-6 radio-button


    【解决方案1】:

    只是为了好玩,这种重构可以避免@Nick Parsons 描述得很好的问题

    const form = document.forms[0];
    // one of the checkboxes checked?
    const checkFirstFieldsetCheckboxes = () =>
      Array.from(document.querySelector("fieldset")
        .querySelectorAll("input[type=checkbox]"))
        .filter(v => v.checked).length > 0;
    // disable all fieldsets except the first
    const disableFieldsets = () => {
      form.reset();
      Array.from(form.querySelectorAll("fieldset")).slice(1)
        .forEach(fieldset => fieldset.disabled = true);
    };
    const enableNext = origin => {
      const nextFieldset = origin.closest("section")
        .nextElementSibling.querySelector("fieldset");
      if (nextFieldset) {
        nextFieldset.disabled = false;
      }
    };
    const fieldsetHandling = evt => {
      const origin = evt.target;
      return !origin.type 
        	? false 
          : origin.type === "radio" 
            	? enableNext(origin) 
              : !checkFirstFieldsetCheckboxes() 
                ? disableFieldsets() 
                : enableNext(origin);
    };
    // main
    disableFieldsets();
    // add handler (event delegation)
    document.addEventListener("click", fieldsetHandling);
    <form method=post action=submit>
      <section>
        <fieldset>
          <legend>First Fieldset</legend>
          <label><input type=checkbox name=First value=A>A</label>
          <label><input type=checkbox name=First value=B>B</label>
          <label><input type=checkbox name=First value=C>C</label>
        </fieldset>
      </section>
    
      <section>
        <fieldset>
          <legend>Second Fieldset</legend>
          <label><input type=radio name=Second value=1.1>1.1</label>
          <label><input type=radio name=Second value=1.2>1.2</label>
          <label><input type=radio name=Second value=1.3>1.3</label>
        </fieldset>
      </section>
    
      <section>
        <fieldset>
          <legend>Third Fieldset</legend>
          <label><input type=radio name=Third value=2.1>2.1</label>
          <label><input type=radio name=Third value=2.2>2.2</label>
          <label><input type=radio name=Third value=2.3>2.3</label>
        </fieldset>
      </section>
    
      <section>
        <fieldset>
          <legend>Fourth Fieldset</legend>
          <label><input type=radio name=Fourth value=3.1>3.1</label>
          <label><input type=radio name=Fourth value=3.2>3.2</label>
          <label><input type=radio name=Fourth value=3.3>3.3</label>
        </fieldset>
      </section>
    
      <input type=submit value=Submit>
    </form>

    【讨论】:

      【解决方案2】:

      在您的部分的change 事件中,您可以通过向函数添加事件参数来分配!event.target.checked,而不是将nextFieldset 分配为禁用:

      document.addEventListener("DOMContentLoaded", _ => {
        const form = document.forms[0]
      
        // First, disable all fieldsets except the first
      
        function disableFieldsets() {
          const disabledFieldsets = form.querySelectorAll(
            "section:not(:first-of-type) fieldset"
          )
      
          for (let i = 0; i < disabledFieldsets.length; i++) {
            disabledFieldsets[i].disabled = true
          }
        }
      
        disableFieldsets()
      
        // Sequentially enable fieldsets on selection
      
        const sections = form.querySelectorAll("section")
      
        sections.forEach(section => {
          section.addEventListener("change", function(event) {
            let nextFieldset = this.nextElementSibling.querySelector("fieldset")
      
            if (nextFieldset) {
              nextFieldset.disabled = !event.target.checked
            }
          })
        })
      
        // Reset form and disable fieldsets after all inputs in the first fieldset are deselected
      
        const firstFieldsetButtons = form.querySelectorAll("[name=First]")
        let isChecked = false
      
        firstFieldsetButtons.forEach(firstFieldsetButton => {
          firstFieldsetButton.addEventListener("click", function(e) {
            if (this.checked) {
              isChecked = true
            } else {
              form.reset()
              disableFieldsets()
            }
          })
        })
      })
      <form method=post action=submit>
        <section>
          <fieldset>
            <legend>First Fieldset</legend>
            <label><input type=checkbox name=First value=A>A</label>
            <label><input type=checkbox name=First value=B>B</label>
            <label><input type=checkbox name=First value=C>C</label>
          </fieldset>
        </section>
      
        <section>
          <fieldset>
            <legend>Second Fieldset</legend>
            <label><input type=radio name=Second value=1.1>1.1</label>
            <label><input type=radio name=Second value=1.2>1.2</label>
            <label><input type=radio name=Second value=1.3>1.3</label>
          </fieldset>
        </section>
      
        <section>
          <fieldset>
            <legend>Third Fieldset</legend>
            <label><input type=radio name=Third value=2.1>2.1</label>
            <label><input type=radio name=Third value=2.2>2.2</label>
            <label><input type=radio name=Third value=2.3>2.3</label>
          </fieldset>
        </section>
      
        <section>
          <fieldset>
            <legend>Fourth Fieldset</legend>
            <label><input type=radio name=Fourth value=3.1>3.1</label>
            <label><input type=radio name=Fourth value=3.2>3.2</label>
            <label><input type=radio name=Fourth value=3.3>3.3</label>
          </fieldset>
        </section>
      
        <input type=submit value=Submit>
      </form>

      【讨论】:

        【解决方案3】:

        每次更改第一个字段集时,您都会启用第二个字段集 - 即使您取消选中复选框也是如此。即使您在“单击”复选框后禁用了字段集,您的 "change" 事件也会在此事件之后运行,从而启用第二个字段集。这可以通过使用标志来指示表单是否已被重置来解决:

        document.addEventListener("DOMContentLoaded", _ => {
          const form = document.forms[0];
        
          // First, disable all fieldsets except the first
        
          function disableFieldsets() {
            const disabledFieldsets = form.querySelectorAll(
              "section:not(:first-of-type) fieldset"
            )
        
            for (let i = 0; i < disabledFieldsets.length; i++) {
              disabledFieldsets[i].disabled = true
            }
          }
        
          disableFieldsets()
        
          // Sequentially enable fieldsets on selection
        
          const sections = form.querySelectorAll("section")
          let reset = false;
          sections.forEach(section => {
            section.addEventListener("change", function() {
              let nextFieldset = this.nextElementSibling.querySelector("fieldset")
              if (nextFieldset && !reset) {
                nextFieldset.disabled = false;
              } else if(reset) {
                reset = false;
              }
            })
          })
        
          // Reset form and disable fieldsets after all inputs in the first fieldset are deselected
        
          const firstFieldsetButtons = form.querySelectorAll("[name=First]")
          let isChecked = false;
        
          firstFieldsetButtons.forEach(firstFieldsetButton => {
            firstFieldsetButton.addEventListener("click", function(e) {
              if (this.checked) {
                isChecked = true;
              } else {
                form.reset();
                disableFieldsets();
                reset = true;
              }
            })
          })
        })
        <form method=post action=submit>    
          <section>
          <fieldset>
            <legend>First Fieldset</legend>
            <label><input type=checkbox name=First value=A>A</label>
            <label><input type=checkbox name=First value=B>B</label>
            <label><input type=checkbox name=First value=C>C</label>
          </fieldset>
          </section>
          
          <section>
          <fieldset>
            <legend>Second Fieldset</legend>
            <label><input type=radio name=Second value=1.1>1.1</label>
            <label><input type=radio name=Second value=1.2>1.2</label>
            <label><input type=radio name=Second value=1.3>1.3</label>
          </fieldset>
          </section>
          
          <section>
          <fieldset>
            <legend>Third Fieldset</legend>
            <label><input type=radio name=Third value=2.1>2.1</label>
            <label><input type=radio name=Third value=2.2>2.2</label>
            <label><input type=radio name=Third value=2.3>2.3</label>
          </fieldset>
          </section>
          
          <section>
          <fieldset>
            <legend>Fourth Fieldset</legend>
            <label><input type=radio name=Fourth value=3.1>3.1</label>
            <label><input type=radio name=Fourth value=3.2>3.2</label>
            <label><input type=radio name=Fourth value=3.3>3.3</label>
          </fieldset>
          </section>
          
          <input type=submit value=Submit>
        </form>

        【讨论】:

        • @Tzar 不用担心 :) 可能有更好的方法来解决这个问题,但我的大脑已经决定停止工作并且似乎无法想出一个。如果我想出一个,我会告诉你的
        猜你喜欢
        • 2018-11-27
        • 2022-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-23
        • 2014-12-09
        • 2016-01-13
        • 2020-09-21
        相关资源
        最近更新 更多