【问题标题】:Angularjs updates the view but not the modelAngularjs 更新视图但不更新模型
【发布时间】:2014-12-09 19:57:07
【问题描述】:

请注意,这与 stackoverflow 上 99% 的相关问题相反。

我的问题是:我有一个依赖选择,当“主”选择更改时,“从”视图会更新,但不是模型。很奇怪。

示例代码:

<!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 }} 的打印值没有变化。

plunker 链接:http://plnkr.co/edit/LjaKgTTfBlczkGuCIhZ1

【问题讨论】:

  • 我猜这是因为 ng-selected 根本不知道模型,它只是设置 selected 属性,并且不会触发任何值更改,因此模型不会得到更新。
  • 为什么不使用 ng-options? ng-selected 不更新 ng-model
  • 您在寻找这样的东西吗? stackoverflow.com/questions/25413071/…
  • @Daniel,以下任何答案是否解决了您的问题?如果是,请接受适当的答案。
  • 哇,stackoverflow 真的应该发送电子邮件……我从来没有收到这一切的通知!我会马上接受的……

标签: angularjs html-select angularjs-model angularjs-watch


【解决方案1】:

Angular 根据模型更改更新视图,并根据用户与视图的交互来更新模型。通过使用ng-selected 手动更改所选选项,angular 没有看到用户选择新选项,因此不会更新slave。并且由于slave 自上次在控件上设置选定选项以来没有更改,因此不会更新选定选项。我认为您不应该同时使用ng-modelng-selected。我认为这完全有道理,并且不是 Angular 中的错误,ng-selected 并不意味着以这种方式使用。想想这段代码:

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

slave 的值应该是什么,应该选择哪个选项?您已经在代码中设置了这两个选项,角度应该对 html 选择做什么?它应该忽略您对“从”值的设置吗?如果masterm2,它是否应该忽略ng-selected 属性,即它应该选择从属2?假设您将master 设置为m1,这会导致ng-selected 将所选选项设为从属1。如果用户随后将选项更改为从属2 会怎样?然后ng-selected 选项不正确。

如果你想在master改变时一次性设置slave的值,你应该创建一个watch在值改变时运行代码:

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

【讨论】:

  • 我接受这个是因为它只有正确的答案,但@new-dev 也说得对:'实际上,实现这个的正确方法是通过 $watcher'
【解决方案2】:

@Shomz 的答案是一种方法,尽管 replace 看起来有点像 hack。

slave 没有更新的原因是因为 Angular 在开发人员不知情的情况下更改 ViewModel 非常小心。通常,ViewModel 应由控制器更改以响应外部事件或由 View 更改 - 以响应用户操作。在这种情况下,更改将响应 selected 属性在所选从属设备上发生更改,因此 Angular 不会更改 slave

另一种思考方式是:如果您没有视图(即&lt;select&gt;),如何更新slave 以响应master 的变化,例如就像对控制器进行单元测试一样。

实际上,实现这一点的正确方法是通过$watcher - 所以我不同意@Shomz 在这一点上。

我还建议评估为什么您需要主服务器和从服务器相互跟踪。如果是这种情况,您应该使用相同的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>   

【讨论】:

  • 是的。我也会选择 ng-options。
  • 对于观察者部分,我的意思是写特定的scope.$watch('master'... 东西,那真的很糟糕。我说替换是纯粹的懒惰。 :) 重点是 ng-selected 只关心 DOM。
  • @Shomz,为什么?如果slavemaster 做了一些有条件的阴影,我会说这的方式。如果它总是相同,那么它应该是相同的 ViewModel 属性
  • 这就是问题所在,我们只能猜测这东西应该做什么。
  • @Shomz,同意 - 但我做了一个(有根据的)猜测:)
【解决方案3】:

Angular 的方法是直接更改从属模型,而不仅仅是 DOM(ng-selected 基本上只是设置 selected 属性,如果它评估为真,没有别的)。从技术上讲,您可以通过添加一个也会更新模型的观察者来解决这个问题,但重写它听起来是一个更好的主意。

这是一个例子,它有点草率,但替换是我在不实际编写一些 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

【讨论】:

  • 我相信最初的问题并不像替换 m 和 s 那样简单.. :D
  • 我也是,但我们不知道 OP 到底想做什么(为什么要两个模型?),替换是我避免创建映射器对象的方法。 :)
  • 没错,ng-options 带有一个对象映射主从属(不喜欢内联它)。
  • 我无法理解 ng-options,它只是按照我给它的任何顺序弄乱了键/值。我很想看到一个使用 ng-options 实现给定值的示例。我最终使用 ng-change 调用更新从属的函数。但是映射器 $watcher 似乎是正确的方法。
猜你喜欢
  • 1970-01-01
  • 2014-02-13
  • 2013-12-02
  • 1970-01-01
  • 1970-01-01
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多