Angularjs обновляет представление, но не модель

Пожалуйста, обратите внимание, что это противоположность 99% связанных вопросов в stackoverflow.

Проблема Mi: у меня есть зависимый выбор, когда изменяется выбор "Мастер", представление "Slave" обновляется, но НЕ моделируется. WEIRD.

Пример кода:

<!DOCTYPE html>
<html ng-app>

<head>
  <script src="https://code.angularjs.org/1.3.5/angular.js"></script>
</head>

<body>
  <select ng-model='master'>
    <option value='m1'>Master 1</option>
    <option value='m2'>Master 2</option>
  </select>
  <select ng-model='slave'>
    <option value='Slave 1 selected' ng-selected='master == "m1"'>Slave 1</option>
    <option value='Slave 2 selected' ng-selected='master == "m2"'>Slave 2</option>
  </select>
  {{ slave }}
</body>

</html>

При изменении выбора мастера вы можете увидеть изменение выбора, но не напечатанное значение для привязки {{slave}}.

Ссылка на плункер: http://plnkr.co/edit/LjaKgTTfBlczkGuCIhZ1

+4
источник поделиться
3 ответа

Angular обновляет представление на основе изменений модели и модели, основанной на взаимодействии пользователя с представлением. Изменяя выбранный вариант вручную с помощью ng-selected, angular не видел, чтобы пользователь выбирал новую опцию и, следовательно, не обновлял slave. А поскольку slave не изменился, так как он последний задал выбранный параметр в элементе управления, он не будет обновлять выбранную опцию. Я не думаю, что вы должны использовать ng-model и ng-selected вместе. Я думаю, что это имеет общий смысл и не является ошибкой в ​​angular, ng-selected просто не предназначен для использования таким образом. Подумайте об этом коде:

$scope.buttonClicked = function () {
  $scope.slave = "Slave 1 selected";
  $scope.master = "m2";
};

Каким должно быть значение slave и какой параметр следует выбрать? Вы установили оба параметра в коде, что должно сделать angular для выбора html? Следует ли игнорировать настройку "ведомого" значения? Если он игнорирует атрибут ng-selected, который говорит, что он должен выбрать slave 2, если master - m2? Скажем, вы установили master в m1, это приводит к тому, что ng-selected делает выбранное ведомое устройство. 1. Что, если пользователь затем изменит параметр на ведомый 2? Опция ng-selected неверна.

Если вы хотите сделать одноразовую настройку ведомого значения при изменении мастера, вы должны создать часы для запуска кода при изменении значения:

$scope.$watch('master', function(newValue, oldValue) {
  if (newValue == 'm1') {
    $scope.slave = 'Slave 1 selected';
  } else if (newValue == 'm2') {
    $scope.slave = 'Slave 2 selected';
  } else {
    $scope.slave = undefined;
  }
});
+1
источник

Ответ @Shomz - один из способов, хотя replace кажется немного взломанным.

Причина, по которой slave не обновляется, связана с тем, что Angular осторожно относится к изменению ViewModel без знаний разработчика. Как правило, ViewModel должен быть изменен либо контроллером в ответ на внешнее событие, либо с помощью действия "Вид - в ответ на действие пользователя". В этом случае изменение было бы ответом на свойство selected, которое было изменено на подчиненном устройстве, поэтому Angular не изменит slave.

Еще один способ подумать о нем: как slave будет обновляться в ответ на изменение в master, если у вас не было View (т.е. <select>), такое как случай с модульным тестированием контроллера.

Правильный способ реализовать это, по сути, через $watcher - поэтому я не согласен с этим с помощью @Shomz.

Я также предложил бы оценить, почему вам нужно как master, так и slave, чтобы заслонять друг друга. Если это так, вы должны использовать тот же ng-model:

<select ng-model="master2" 
       ng-options="val.k as val.v for val in [{k: 'm1', v: 'Master1'}, {k: 'm2', v: 'Master2'}]">
</select>
<select ng-model="master2" 
       ng-options="val.k as val.v for val in [{k: 'm1', v: 'Slave 1'}, {k: 'm2', v: 'Slave 2'}]">
</select>   
+1
источник

Подходом Angular к этому было бы изменение подчиненной модели напрямую, а не только DOM (ng-selected в основном просто устанавливает атрибут selected, если он оценивает значение true, ничего больше). Технически вы можете взломать это, добавив наблюдателя, который также будет обновлять модель, но переписывание это звучит как гораздо лучшая идея.

Вот пример, это немного неряшливо, но замена была самой быстрой вещью, которую я мог бы сделать, не написав какую-нибудь JS (но вы поняли):

  <select ng-model='master' ng-change="slave = master.replace('m', 's')">
    <option value='m1'>Master 1</option>
    <option value='m2'>Master 2</option>
  </select>
  <select ng-model='slave'>
    <option value='s1' >Slave 1</option>
    <option value='s2' >Slave 2</option>
  </select>

http://plnkr.co/edit/WT7vb7yvtcvaUPUwGXdI?p=preview

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос