ng-change事件仅在使用ng-repeat创建时为每个单选按钮触发一次

时间:2014-05-21 17:37:17

标签: angularjs angularjs-directive

我创建了一个带有单选按钮的AngularJS指令,用于控制我的页面将查询的环境并将其添加到我的页面。我正在使用双向绑定将名为environment的局部范围变量映射到具有相同名称的app变量。当我在模板中明确创建单选按钮时,它似乎运行良好(在我的实际代码中我使用templateUrl代替,但仍然有相同的问题)。

<div>
    <label><input type="radio" name="env" ng-model="environment" ng-change="changeEnvironment(1)" value="1" />Testing</label>
    <label><input type="radio" name="env" ng-model="environment" ng-change="changeEnvironment(2)" value="2" />Production</label>
</div>

我可以根据需要多次选择每个选项,并且值一直到应用程序的范围变量。

我想更改单选按钮的创建,以便在选择对象数组上使用ng-repeat。它创建选项,并捕获ngChange事件,但每次选择只捕获一次。

<label ng-repeat="choice in choices">
    <input type="radio" name="env" ng-model="environment" ng-change="changeEnvironment(choice)" value="{{ choice.id }}" />{{ choice.name }}
</label>

Here is the working version fiddle以及我的指令代码的相关部分:

template: '<div>'
            + '<label><input type="radio" name="env" ng-model="environment" ng-change="changeEnvironment(1)" value="1" />Testing</label>'
            + '<label><input type="radio" name="env" ng-model="environment" ng-change="changeEnvironment(2)" value="2" />Production</label>'
            + '<div>Directive environment: {{ environment }}</div>'
            + '</div>',
link: function(scope, element, attributes) {

    scope.changeEnvironment = function(choiceID) {
        console.log('SELECTED environment ' + choiceID);
        scope.environment = choiceID;
        console.log('directive environment = ' + scope.environment);
    };

}

here is the version that only works once

template: '<div><label ng-repeat="choice in choices">'
            + '<input type="radio" name="env" ng-model="environment" ng-change="changeEnvironment(choice)" value="{{ choice.id }}" />{{ choice.name }}'
            + '</label>'
            + '<div>Directive environment: {{ environment }}</div>'
            + '</div>',
link: function(scope, element, attributes) {
    scope.choices = [
        { id: 1, name: "Testing" },
        { id: 2, name: "Production" }
    ];

    scope.changeEnvironment = function(choice) {
        console.log('SELECTED environment ' + choice.id);
        scope.environment = choice.id;
        console.log('directive environment = ' + scope.environment);
    };

}

我对AngularJS来说是全新的,所以我完全有可能犯下一个非常基本的错误。有人能指出我正确的方向吗?

更新根据callmekatootie的建议,我将相关事件从ng-change更改为ng-click,并且每次都会触发。这将暂时解决,但我最初使用ng-change,因为我认为ng-click不适用于点击文字标签而非输入本身造成的更改,但实际上确实如此。但仍然不明白为什么ng-change只会发射一次。

3 个答案:

答案 0 :(得分:7)

问题的原因是ngRepeat将为其子项创建新的范围(以及原型继承如何影响范围)。

Angular wiki 对范围继承的工作原理(以及常见的陷阱)有相当好的(彻底的)解释。

This answer 对一个非常相似(实际上)的问题几乎解释了这个问题。

在您的具体情况下,您可以介绍一个对象(例如local)并指定environment作为其属性):

scope.local = {environment: scope.environment};
scope.changeEnvironment = function(choice) {
    scope.environment = choice.id;
};

然后你应该将你的模板绑定到“encaplulated”属性:

<input ... ng-model="local.environement" ... />

另请参阅此 short demo


<强>更新

这个答案旨在指出问题的根源 绝对建议使用不同的实现(如tasseKATTLeon提议的实现)(以及更多“Angularish”)。

答案 1 :(得分:4)

使用对象而不是原始值:

app.controller('mainController', ['$scope', function (scope) {
  scope.environment = { value: '' };
}]);

删除ng-change$watchng-model就足够了(除非我误解了用例)。

演示: http://jsfiddle.net/GLAQ8/

可以找到关于原型继承的非常好的帖子here

答案 2 :(得分:2)

你在ng-change事件中使用enviorement而不是$ parent.enviorement,它与重复范围有关,而不是enviorement变量所在的ng-repeat父范围,

http://jsfiddle.net/cJ4Wb/7/

ng-model="$parent.enviroment"

请注意,在这种情况下,您甚至不需要事件来更新环境,并且模型中的任何更改都会在单选按钮中显示