在选择最后一个按钮之前,AngularJS 单选按钮未标记为 $dirty

Posted

技术标签:

【中文标题】在选择最后一个按钮之前,AngularJS 单选按钮未标记为 $dirty【英文标题】:AngularJS radio buttons not marked $dirty until last button selected 【发布时间】:2014-04-06 13:11:04 【问题描述】:

我创建了这个简单的例子:http://jsfiddle.net/5Bh59/。

如果您在 AngularJS 1.2.1 和 1.1.1 之间切换,您会看到单选按钮在任一版本中都无法正常工作。如果你看单选按钮的$dirty 字段,1) 对于版本 1.1.1,它只会在点击第一个按钮时设置,2) 对于版本 1.2.1,它只会在最后一个按钮被点击时设置点击。

我读了这个答案:AngularJS Radio group not setting $dirty on field 但我不太明白答案。不仅如此,fiddler 示例也演示了相同的行为。

那么,这是 AngularJS 中的一个错误吗?我该如何解决?

【问题讨论】:

那行得通。我很惊讶 $valid 变成 true 对于两个控件,即使只选择了一个。 我猜那是因为他们使用相同的 ng-model,所以所有的输入都可以判断组中是否有一个被选中。 问题是每个人现在也有自己的$dirty。我只喜欢在控件标记为 $dirty 时显示验证。 您可以在所有单选按钮周围包裹一个 ng-form 并将其命名为“radioGroup”,然后只要单击任何单选按钮,它就会被标记为 $dirty。我将添加另一个小提琴。 【参考方案1】:

您需要为每个单选按钮输入一个不同的名称,或者您需要将每个单选按钮包装在一个 ng-form 中(每个单选按钮都有不同的名称)。如果在同一个表单中使用两个同名的输入,则只有最后一个会绑定到 FormController 上的属性。如果您使用不同的名称,那么每个输入在 FormController 上都有自己的属性。

每个单选按钮具有不同名称的示例: http://jsfiddle.net/BEU3V/

<form name="form" novalidate>
    <input type="radio" 
        name="myRadio1" 
        ng-model="myRadio" 
        ng-click="" 
        value="Rejected"
        required>Rejected<br />
    <input type="radio" 
        name="myRadio2" 
        ng-model="myRadio"
        ng-click=""
        value="Approved"
        required>Approved<br />
   Form $dirty: form.$dirty<br />
   Field1 $dirty: form.myRadio1.$dirty<br />
   Field1 $dirty: form.myRadio2.$dirty<br />
   Value: myRadio
</form>

使用 ng-form 包装的示例: http://jsfiddle.net/39Rrm/1/

<form name="form" novalidate>
    <ng-form name="form1">
    <input type="radio" 
        name="myRadio" 
        ng-model="myRadio" 
        ng-click="" 
        value="Rejected"
        required>Rejected<br />
        </ng-form>
    <ng-form name="form2">    
    <input type="radio" 
        name="myRadio" 
        ng-model="myRadio"
        ng-click=""
        value="Approved"
        required>Approved<br />
        </ng-form>
   Form $dirty: form.$dirty<br />
   Field1 $dirty: form.form1.myRadio.$dirty<br />
   Field2 $dirty: form.form2.myRadio.$dirty<br />
   Value: myRadio
   </form>

如果您想对单选组进行一次检查,您可以将所有单选按钮包装在它们自己的 ng-form 中,并将其命名为 name="radioGroup"。

http://jsfiddle.net/6VVBL/

<form name="form" novalidate>
    <ng-form name="radioGroup">
    <input type="radio" 
        name="myRadio1" 
        ng-model="myRadio" 
        ng-click="" 
        value="Rejected"
        required>Rejected<br />
    <input type="radio" 
        name="myRadio2" 
        ng-model="myRadio"
        ng-click=""
        value="Approved"
        required>Approved<br />
        </ng-form>
   Form $dirty: form.$dirty<br />
   Group $valid: form.radioGroup.$valid<br />
   Group $dirty: form.radioGroup.$dirty<br />
   Value: myRadio
   </form>

【讨论】:

我最终选择了选项 #3。我正在使用一个验证指令,它将用&lt;div class="has-error"&gt; 包围一个控件并添加一个描述错误的&lt;span&gt;。遗憾的是,它不起作用,因为有两个具有相同名称的控件,并且它仅适用于 ngModel,而不适用于 form。我只是复制了逻辑,使它与外部形式一起工作,现在一切正常。 在一个地方总结所有不同的方法也是一件好事。 觉得“如果你在同一个表单中使用两个同名的输入,那么只有最后一个会被绑定到表单上的属性”。 html 要求来自同一组的收音机具有相同的名称。然而它会在 Angular 中做这个奇怪的事情......也许 Angular 需要重新审视它如何处理收音机/复选框 如果想使用$touched 属性,这也是行不通的。实际引入类似于 Material Design 的 md-radio-group directive 的不同/自定义指令可能是有意义的【参考方案2】:

这个答案是相关的,但可能并不完全适用,但是在找到并阅读了这个项目后,我觉得提供它很有价值,而且我没有足够的分数来评论一个答案(我认为这会是一个更适当的回应方式)。

我的问题是我想显示一个必需的错误(使用 ng-messages),但是当您通过/越过单选按钮组时,除非您从下一个 UI 元素返回,否则 $touched 不会变为真到组的最后一个单选按钮。 (当我的表单呈现单选按钮时,我希望用户做出选择,而不是依赖用户接受默认值。)

这是我的代码:

<div class="form-group" ng-class="'has-error': pet.genderId.$invalid && pet.genderId.$touched">
    <label class="control-label">
        What is your pet's gender?
        <span ng-messages="pet.genderId.$error" ng-show="pet.genderId.$invalid && pet.genderId.$touched">
            <span ng-message="required">(required)</span>
        </span>
    </label>
    <div>
        <label class="radio-inline"><input type="radio" ng-model="genderId" name="genderId" value="1" required ng-blur="pet.genderId.$setTouched();" />Male</label>
        <label class="radio-inline"><input type="radio" ng-model="genderId" name="genderId" value="2" required ng-blur="pet.genderId.$setTouched();" />Female</label>
        <label class="radio-inline"><input type="radio" ng-model="genderId" name="genderId" value="3" required ng-blur="pet.genderId.$setTouched();" />Not sure</label>
    </div>
</div>

“魔术”是添加 ng-blur 属性来设置“已触摸”我自己,即使只有第一个单选按钮被选中。

您可以通过在 ng-changed 属性中调用 $setDirty() 对 $dirty 使用类似的策略。

【讨论】:

以上是关于在选择最后一个按钮之前,AngularJS 单选按钮未标记为 $dirty的主要内容,如果未能解决你的问题,请参考以下文章

Python Tkinter 中的单选按钮值

如何在提交前选择单选按钮

验证单选按钮AngularJS

将下拉选择输入转换为需要选择一个的单选按钮

单选按钮值和提交按钮

如何在表单之外制作单选按钮?