Событие ng-change срабатывает только один раз для каждого переключателя при создании с помощью ng-repeat
Я создал директиву 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>
Я могу выбрать каждый выбор столько раз, сколько хочу, и значение пузырится до переменной области приложения.
Я хотел изменить создание переключателей, чтобы использовать 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>
Вот скрипта рабочей версии и соответствующие части моего директивного кода:
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);
};
}
И вот версия, которая работает только один раз:
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
срабатывает только один раз.
Ответы
Ответ 1
Используйте объект вместо примитивного значения:
app.controller('mainController', ['$scope', function (scope) {
scope.environment = { value: '' };
}]);
Удалите ng-change
и $watch
. ng-model
будет достаточно (если я не ошибаюсь в случае использования).
Демо: http://jsfiddle.net/GLAQ8/
Очень хорошее сообщение о прототипном наследовании можно найти здесь.
Ответ 2
Причиной проблемы является то, что ngRepeat
создаст новые области для своих дочерних элементов (наряду с тем, как прототипное наследование влияет на области видимости).
Angular wiki имеет довольно хорошее (и полное) объяснение того, как работает наследование областей ( и общие подводные камни).
Этот ответ к очень похожей проблеме (в природе) в значительной степени объясняет эту проблему.
В вашем конкретном случае вы можете ввести объект (например, local
) и назначить environment
как его свойство):
scope.local = {environment: scope.environment};
scope.changeEnvironment = function(choice) {
scope.environment = choice.id;
};
Затем вы должны привязать свой шаблон к этому свойству "encaplulated":
<input ... ng-model="local.environement" ... />
См. также эту короткую демонстрацию.
UPDATE
Этот ответ намеревается указать корень проблемы.
Разная реализация (например, предложенная tasseKATT или Leon), безусловно, рекомендуется (и еще более "Угловая" ").
Ответ 3
вы используете enviorement вместо $parent.enviorement в своем событии ng-change, которое привязано к области повтора, а не к родительской области ng-repeat, в которой живет переменная envorment,
http://jsfiddle.net/cJ4Wb/7/
ng-model="$parent.enviroment"
обратите внимание, что в этом случае вам даже не нужны события, чтобы обновлять настройки и любые изменения в модели будут обновляться в переключателях