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

时间:2021-12-24 14:23:11

I have created an AngularJS directive with radio buttons to control which environment my page will query against and added it to my page. I am using a two-way binding to map a local scope variable called environment to an app variable with the same name. It seems to work well when I create the radio buttons explicitly in the template (in my actual code I'm using templateUrl instead, but still have the same problem).

我创建了一个带有单选按钮的AngularJS指令来控制我的页面要查询的环境,并将其添加到我的页面中。我使用一个双向绑定将一个名为environment的局部范围变量映射到一个同名的应用程序变量。当我在模板中显式地创建单选按钮时(在我的实际代码中,我使用的是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>

I can select each choice as many times as I want, and the value bubbles all the way up to the app's scope variable.

我可以任意选择每个选项,而值气泡一直到应用程序的范围变量。

I wanted to change the creation of the radio buttons to use ng-repeat on an array of choice objects. It creates the options, and it captures the ngChange event, but only once for each choice.

我想更改单选按钮的创建,以便在选择对象的数组中使用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 and the relevant parts of my directive code:

以下是我的指令代码的工作版本小提琴和相关部分:

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

}

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

}

I'm brand-new to AngularJS, so it's entirely possible I'm making a very basic mistake. Can anyone point me in the right direction?

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

UPDATE As per callmekatootie's suggestion, I changed the event in question from ng-change to ng-click, and it fires every time. That will do as a work-around for now, but I originally used ng-change because I didn't think ng-click would apply to changes caused by clicking on the text label rather than the input itself, but in fact it does. Still don't get why ng-change only fires once, though.

根据callmekatootie的建议进行更新,我将问题事件从ng更改更改为ng-click,并且每次都会触发。这将暂时作为一个解决方案,但我最初使用ng-change,因为我不认为nclick会应用于通过单击文本标签而不是输入本身引起的更改,但实际上确实如此。但是,还是不明白为什么ng-change只触发一次。

3 个解决方案

#1


4  

Use an object instead of a primitive value:

使用对象而不是原始值:

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

Remove ng-change and $watch. ng-model will be enough (unless I'm misunderstanding the use case).

删除ng-change和美元的手表。ng-model就足够了(除非我误解了用例)。

Demo: http://jsfiddle.net/GLAQ8/

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

Very good post on prototypal inheritance can be found here.

关于原型继承的很好的文章可以在这里找到。

#2


7  

The cause of the problem is that ngRepeat will create new scopes for its children (along with how prototypal inheritance affects scopes).

问题的原因是,ngRepeat将为它的孩子创建新的作用域(以及原型继承如何影响作用域)。

The Angular wiki has a fairly good (and thorough) explanation of how scope inheritance works (and the common pitfalls).

有棱角的wiki对范围继承如何工作(以及常见的缺陷)有一个相当好的(和全面的)解释。

This answer to a very similar (in nature) problem pretty much explains the issue.

这个对一个非常相似(本质上)的问题的回答几乎可以解释这个问题。

In your specific case, you could introduse an object (e.g. local) and assign environment as its property):

在您的特定情况下,您可以使用一个对象(例如本地),并将环境作为其属性):

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

Then you should bind your template to that "encaplulated" property:

然后,您应该将模板绑定到“封装”属性:

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

See, also, this short demo.

这是一个简短的演示。


UPDATE

更新

This answer intends to point out the root of the issue.
A different implementation (like the ones proposed by tasseKATT or Leon) is definitely recommended (and way more "Angularish").

这个答案意在指出问题的根源。一个不同的实现(如tasseKATT或Leon所提出的)是绝对推荐的(而且更加“Angularish”)。

#3


2  

you are using enviorement instead of $parent.enviorement in your ng-change event which is tied to the repeat scope not the the ng-repeat parent scope where the enviorement variable lives,

你使用的是enviorement,而不是$parent。环境变化事件中的环境与重复范围有关而不是环境变量所在的ng-重复父范围,

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

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

ng-model="$parent.enviroment"

notice that in this case you don't even need the events to keep enviorement updated and any changes in the model will refelct in the radio buttons

注意,在这种情况下,您甚至不需要事件来更新enviorement,模型中的任何更改都将在单选按钮中重新执行

#1


4  

Use an object instead of a primitive value:

使用对象而不是原始值:

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

Remove ng-change and $watch. ng-model will be enough (unless I'm misunderstanding the use case).

删除ng-change和美元的手表。ng-model就足够了(除非我误解了用例)。

Demo: http://jsfiddle.net/GLAQ8/

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

Very good post on prototypal inheritance can be found here.

关于原型继承的很好的文章可以在这里找到。

#2


7  

The cause of the problem is that ngRepeat will create new scopes for its children (along with how prototypal inheritance affects scopes).

问题的原因是,ngRepeat将为它的孩子创建新的作用域(以及原型继承如何影响作用域)。

The Angular wiki has a fairly good (and thorough) explanation of how scope inheritance works (and the common pitfalls).

有棱角的wiki对范围继承如何工作(以及常见的缺陷)有一个相当好的(和全面的)解释。

This answer to a very similar (in nature) problem pretty much explains the issue.

这个对一个非常相似(本质上)的问题的回答几乎可以解释这个问题。

In your specific case, you could introduse an object (e.g. local) and assign environment as its property):

在您的特定情况下,您可以使用一个对象(例如本地),并将环境作为其属性):

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

Then you should bind your template to that "encaplulated" property:

然后,您应该将模板绑定到“封装”属性:

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

See, also, this short demo.

这是一个简短的演示。


UPDATE

更新

This answer intends to point out the root of the issue.
A different implementation (like the ones proposed by tasseKATT or Leon) is definitely recommended (and way more "Angularish").

这个答案意在指出问题的根源。一个不同的实现(如tasseKATT或Leon所提出的)是绝对推荐的(而且更加“Angularish”)。

#3


2  

you are using enviorement instead of $parent.enviorement in your ng-change event which is tied to the repeat scope not the the ng-repeat parent scope where the enviorement variable lives,

你使用的是enviorement,而不是$parent。环境变化事件中的环境与重复范围有关而不是环境变量所在的ng-重复父范围,

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

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

ng-model="$parent.enviroment"

notice that in this case you don't even need the events to keep enviorement updated and any changes in the model will refelct in the radio buttons

注意,在这种情况下,您甚至不需要事件来更新enviorement,模型中的任何更改都将在单选按钮中重新执行